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::SC;
use std::ffi::CStr;
use crate::core::StreamingBufferConfig;
pub use suricata_derive::AppLayerEvent;
#[repr(C)]
pub struct StreamSlice {
input: *const u8,
input_len: u32,
flags: u8,
offset: u64,
}
impl StreamSlice {
#[cfg(test)]
pub fn from_slice(slice: &[u8], flags: u8, offset: u64) -> Self {
Self {
input: slice.as_ptr(),
input_len: slice.len() as u32,
flags,
offset
}
}
pub fn is_gap(&self) -> bool {
self.input.is_null() && self.input_len > 0
}
pub fn gap_size(&self) -> u32 {
self.input_len
}
pub fn as_slice(&self) -> &[u8] {
unsafe { std::slice::from_raw_parts(self.input, self.input_len as usize) }
}
pub fn is_empty(&self) -> bool {
self.input_len == 0
}
pub fn len(&self) -> u32 {
self.input_len
}
pub fn offset_from(&self, slice: &[u8]) -> u32 {
self.len() - slice.len() as u32
}
pub fn flags(&self) -> u8 {
self.flags
}
}
#[repr(C)]
#[derive(Default, Debug,PartialEq, Eq)]
pub struct AppLayerTxConfig {
log_flags: u8,
}
impl AppLayerTxConfig {
pub fn new() -> Self {
Self {
log_flags: 0,
}
}
}
#[repr(C)]
#[derive(Debug, PartialEq, Eq)]
pub struct AppLayerTxData {
pub config: AppLayerTxConfig,
logged: LoggerFlags,
pub files_opened: u32,
pub files_logged: u32,
pub files_stored: u32,
pub file_flags: u16,
pub file_tx: u8,
detect_flags_ts: u64,
detect_flags_tc: u64,
de_state: *mut DetectEngineState,
pub events: *mut core::AppLayerDecoderEvents,
}
impl Default for AppLayerTxData {
fn default() -> Self {
Self::new()
}
}
impl Drop for AppLayerTxData {
fn drop(&mut self) {
if !self.de_state.is_null() {
core::sc_detect_engine_state_free(self.de_state);
}
if !self.events.is_null() {
core::sc_app_layer_decoder_events_free_events(&mut self.events);
}
}
}
impl AppLayerTxData {
pub fn new() -> Self {
Self {
config: AppLayerTxConfig::new(),
logged: LoggerFlags::new(),
files_opened: 0,
files_logged: 0,
files_stored: 0,
file_flags: 0,
file_tx: 0,
detect_flags_ts: 0,
detect_flags_tc: 0,
de_state: std::ptr::null_mut(),
events: std::ptr::null_mut(),
}
}
pub fn for_direction(direction: Direction) -> Self {
let (detect_flags_ts, detect_flags_tc) = match direction {
Direction::ToServer => (0, APP_LAYER_TX_SKIP_INSPECT_FLAG),
Direction::ToClient => (APP_LAYER_TX_SKIP_INSPECT_FLAG, 0),
};
Self {
config: AppLayerTxConfig::new(),
logged: LoggerFlags::new(),
files_opened: 0,
files_logged: 0,
files_stored: 0,
file_flags: 0,
file_tx: 0,
detect_flags_ts,
detect_flags_tc,
de_state: std::ptr::null_mut(),
events: std::ptr::null_mut(),
}
}
pub fn init_files_opened(&mut self) {
self.files_opened = 1;
}
pub fn incr_files_opened(&mut self) {
self.files_opened += 1;
}
pub fn set_event(&mut self, event: u8) {
core::sc_app_layer_decoder_events_set_event_raw(&mut self.events, event);
}
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);
self.file_flags |= state_flags;
}
}
}
#[macro_export]
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
{
let tx = &mut *(tx as *mut $type);
&mut tx.tx_data
}
}
}
#[repr(C)]
#[derive(Default,Debug,PartialEq, Eq,Copy,Clone)]
pub struct AppLayerStateData {
pub file_flags: u16,
}
impl AppLayerStateData {
pub fn new() -> Self {
Self {
file_flags: 0,
}
}
}
#[macro_export]
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
{
let state = &mut *(state as *mut $type);
&mut state.state_data
}
}
}
#[repr(C)]
#[derive(Default,Debug,PartialEq, Eq,Copy,Clone)]
pub struct AppLayerResult {
pub status: i32,
pub consumed: u32,
pub needed: u32,
}
impl AppLayerResult {
pub fn ok() -> Self {
Default::default()
}
pub fn err() -> Self {
return Self {
status: -1,
..Default::default()
};
}
pub fn incomplete(consumed: u32, needed: u32) -> Self {
return Self {
status: 1,
consumed,
needed,
};
}
pub fn is_incomplete(self) -> bool {
self.status == 1
}
}
impl From<bool> for AppLayerResult {
fn from(v: bool) -> Self {
if !v {
Self::err()
} else {
Self::ok()
}
}
}
impl From<i32> for AppLayerResult {
fn from(v: i32) -> Self {
if v < 0 {
Self::err()
} else {
Self::ok()
}
}
}
#[repr(C)]
pub struct RustParser {
pub name: *const c_char,
pub default_port: *const c_char,
pub ipproto: u8,
pub probe_ts: Option<ProbeFn>,
pub probe_tc: Option<ProbeFn>,
pub min_depth: u16,
pub max_depth: u16,
pub state_new: StateAllocFn,
pub state_free: StateFreeFn,
pub parse_ts: ParseFn,
pub parse_tc: ParseFn,
pub get_tx_count: StateGetTxCntFn,
pub get_tx: StateGetTxFn,
pub tx_free: StateTxFreeFn,
pub tx_comp_st_ts: c_int,
pub tx_comp_st_tc: c_int,
pub tx_get_progress: StateGetProgressFn,
pub get_eventinfo: Option<GetEventInfoFn>,
pub get_eventinfo_byid: Option<GetEventInfoByIdFn>,
pub localstorage_new: Option<LocalStorageNewFn>,
pub localstorage_free: Option<LocalStorageFreeFn>,
pub get_tx_files: Option<GetTxFilesFn>,
pub get_tx_iterator: Option<GetTxIteratorFn>,
pub get_state_data: GetStateDataFn,
pub get_tx_data: GetTxDataFn,
pub apply_tx_config: Option<ApplyTxConfigFn>,
pub flags: u32,
pub truncate: Option<TruncateFn>,
pub get_frame_id_by_name: Option<GetFrameIdByName>,
pub get_frame_name_by_id: Option<GetFrameNameById>,
}
#[macro_export]
macro_rules! build_slice {
($buf:ident, $len:expr) => ( std::slice::from_raw_parts($buf, $len) );
}
#[macro_export]
macro_rules! cast_pointer {
($ptr:ident, $ty:ty) => ( &mut *($ptr as *mut $ty) );
}
#[allow(non_snake_case)]
#[repr(C)]
pub struct AppLayerGetFileState {
pub fc: *mut FileContainer,
pub cfg: *const StreamingBufferConfig,
}
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;
extern {
pub fn AppLayerRegisterProtocolDetection(parser: *const RustParser, enable_default: c_int) -> AppProto;
pub fn AppLayerRegisterParserAlias(parser_name: *const c_char, alias_name: *const c_char);
}
#[allow(non_snake_case)]
pub unsafe fn AppLayerRegisterParser(parser: *const RustParser, alproto: AppProto) -> c_int {
(SC.unwrap().AppLayerRegisterParser)(parser, alproto)
}
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 AppLayerRequestProtocolTLSUpgrade(flow: *const Flow) -> bool;
}
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);
pub const APP_LAYER_TX_SKIP_INSPECT_FLAG: u64 = BIT_U64!(62);
extern {
pub fn AppLayerParserStateSetFlag(state: *mut c_void, flag: u16);
pub fn AppLayerParserStateIssetFlag(state: *mut c_void, flag: u16) -> u16;
pub fn AppLayerParserSetStreamDepth(ipproto: u8, alproto: AppProto, stream_depth: u32);
pub fn AppLayerParserConfParserEnabled(ipproto: *const c_char, proto: *const c_char) -> c_int;
}
#[repr(C)]
pub struct AppLayerGetTxIterTuple {
tx_ptr: *mut std::os::raw::c_void,
tx_id: u64,
has_next: bool,
}
impl AppLayerGetTxIterTuple {
pub fn with_values(tx_ptr: *mut std::os::raw::c_void, tx_id: u64, has_next: bool) -> AppLayerGetTxIterTuple {
AppLayerGetTxIterTuple {
tx_ptr, tx_id, has_next,
}
}
pub fn not_found() -> AppLayerGetTxIterTuple {
AppLayerGetTxIterTuple {
tx_ptr: std::ptr::null_mut(), tx_id: 0, has_next: false,
}
}
}
#[repr(C)]
#[derive(Default, Debug,PartialEq, Eq)]
pub struct LoggerFlags {
flags: u32,
}
impl LoggerFlags {
pub fn new() -> Self {
Default::default()
}
pub fn get(&self) -> u32 {
self.flags
}
pub fn set(&mut self, bits: u32) {
self.flags = bits;
}
}
pub trait AppLayerEvent {
fn from_id(id: i32) -> Option<Self> where Self: std::marker::Sized;
fn to_cstring(&self) -> &str;
fn from_string(s: &str) -> Option<Self> where Self: std::marker::Sized;
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,
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,
event_type: *mut core::AppLayerEventType,
) -> i8;
}
#[inline(always)]
pub unsafe fn get_event_info<T: AppLayerEvent>(
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() {
return -1;
}
let event = match CStr::from_ptr(event_name).to_str().map(T::from_string) {
Ok(Some(event)) => event.as_i32(),
_ => -1,
};
*event_type = core::AppLayerEventType::APP_LAYER_EVENT_TYPE_TRANSACTION;
*event_id = event as std::os::raw::c_int;
return 0;
}
#[inline(always)]
pub unsafe fn get_event_info_by_id<T: AppLayerEvent>(
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) {
*event_name = e.to_cstring().as_ptr() as *const std::os::raw::c_char;
*event_type = core::AppLayerEventType::APP_LAYER_EVENT_TYPE_TRANSACTION;
return 0;
}
return -1;
}
pub trait Transaction {
fn id(&self) -> u64;
}
pub trait State<Tx: Transaction> {
fn get_transaction_count(&self) -> usize;
fn get_transaction_by_index(&self, index: usize) -> Option<&Tx>;
fn get_transaction_iterator(&self, min_tx_id: u64, state: &mut u64) -> AppLayerGetTxIterTuple {
let mut index = *state as usize;
let len = self.get_transaction_count();
while index < len {
let tx = self.get_transaction_by_index(index).unwrap();
if tx.id() < min_tx_id + 1 {
index += 1;
continue;
}
*state = index as u64;
return AppLayerGetTxIterTuple::with_values(
tx as *const _ as *mut _,
tx.id() - 1,
len - index > 1,
);
}
return AppLayerGetTxIterTuple::not_found();
}
}
pub unsafe extern "C" fn state_get_tx_iterator<S: State<Tx>, 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 {
let state = cast_pointer!(state, S);
state.get_transaction_iterator(min_tx_id, istate)
}
pub trait AppLayerFrameType {
fn from_u8(value: u8) -> Option<Self> where Self: std::marker::Sized;
fn as_u8(&self) -> u8;
fn from_str(s: &str) -> Option<Self> where Self: std::marker::Sized;
fn to_cstring(&self) -> *const std::os::raw::c_char;
unsafe extern "C" fn ffi_id_from_name(name: *const std::os::raw::c_char) -> i32 where Self: Sized {
if name.is_null() {
return -1;
}
let frame_id = if let Ok(s) = std::ffi::CStr::from_ptr(name).to_str() {
Self::from_str(s).map(|t| t.as_u8() as i32).unwrap_or(-1)
} else {
-1
};
frame_id
}
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)
}
}