Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/userguide/rules/snmp-keywords.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ snmp.version

SNMP protocol version (integer). Expected values are 1, 2 (for version 2c) or 3.

snmp.version uses an, :ref:` unsigned 32-bits integer <rules-integer-keywords>`.

Syntax::

snmp.version:[op]<number>
Expand Down Expand Up @@ -69,6 +71,8 @@ snmp.pdu_type

SNMP PDU type (integer).

snmp.pdu_type uses an, :ref:` unsigned 32-bits integer <rules-integer-keywords>`.

Common values are:

- 0: GetRequest
Expand Down
2 changes: 1 addition & 1 deletion examples/lib/simple/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ simple_SOURCES = main.c
AM_CPPFLAGS = -I$(top_srcdir)/src

simple_LDFLAGS = $(all_libraries) $(SECLDFLAGS)
simple_LDADD = $(top_builddir)/src/libsuricata_c.a ../../$(RUST_SURICATA_LIB) $(RUST_LDADD)
simple_LDADD = "-Wl,--start-group,$(top_builddir)/src/libsuricata_c.a,../../$(RUST_SURICATA_LIB),--end-group" $(RUST_LDADD)
if HTP_LDADD
simple_LDADD += ../../$(HTP_LDADD)
endif
Expand Down
1 change: 1 addition & 0 deletions rust/cbindgen.toml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ include = [
"QuicState",
"QuicTransaction",
"FtpEvent",
"SCSigTableElmt",
]

# A list of items to not include in the generated bindings
Expand Down
61 changes: 61 additions & 0 deletions rust/src/detect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ pub mod uri;
pub mod requires;
pub mod tojson;

use crate::core::AppProto;
use std::os::raw::{c_int, c_void};

/// EnumString trait that will be implemented on enums that
/// derive StringEnum.
pub trait EnumString<T> {
Expand All @@ -43,6 +46,64 @@ pub trait EnumString<T> {
fn from_str(s: &str) -> Option<Self> where Self: Sized;
}

#[repr(C)]
#[allow(non_snake_case)]
pub struct SCSigTableElmt {
pub name: *const libc::c_char,
pub desc: *const libc::c_char,
pub url: *const libc::c_char,
pub flags: u16,
pub Setup: unsafe extern "C" fn(
de: *mut c_void,
s: *mut c_void,
raw: *const std::os::raw::c_char,
) -> c_int,
pub Free: Option<unsafe extern "C" fn(de: *mut c_void, ptr: *mut c_void)>,
pub AppLayerTxMatch: Option<
unsafe extern "C" fn(
de: *mut c_void,
f: *mut c_void,
flags: u8,
state: *mut c_void,
tx: *mut c_void,
sig: *const c_void,
ctx: *const c_void,
) -> c_int,
>,
}

pub(crate) const SIGMATCH_NOOPT: u16 = 1; // BIT_U16(0) in detect.h
pub(crate) const SIGMATCH_INFO_STICKY_BUFFER: u16 = 0x200; // BIT_U16(9)

extern {
pub fn DetectBufferSetActiveList(de: *mut c_void, s: *mut c_void, bufid: c_int) -> c_int;
pub fn DetectHelperGetData(
de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8,
tx: *const c_void, list_id: c_int,
get_buf: unsafe extern "C" fn(*const c_void, u8, *mut *const u8, *mut u32) -> bool,
) -> *mut c_void;
pub fn DetectHelperBufferMpmRegister(
name: *const libc::c_char, desc: *const libc::c_char, alproto: AppProto, toclient: bool,
toserver: bool,
get_data: unsafe extern "C" fn(
*mut c_void,
*const c_void,
*const c_void,
u8,
*const c_void,
i32,
) -> *mut c_void,
) -> c_int;
pub fn DetectHelperKeywordRegister(kw: *const SCSigTableElmt) -> c_int;
pub fn DetectHelperBufferRegister(
name: *const libc::c_char, alproto: AppProto, toclient: bool, toserver: bool,
) -> c_int;
pub fn DetectSignatureSetAppProto(s: *mut c_void, alproto: AppProto) -> c_int;
pub fn SigMatchAppendSMToList(
de: *mut c_void, s: *mut c_void, kwid: c_int, ctx: *const c_void, bufid: c_int,
) -> *mut c_void;
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
263 changes: 236 additions & 27 deletions rust/src/snmp/detect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,42 +17,251 @@

// written by Pierre Chifflier <chifflier@wzdftpd.net>

use crate::snmp::snmp::SNMPTransaction;
use super::snmp::{SNMPTransaction, ALPROTO_SNMP};
use crate::detect::uint::{
rs_detect_u32_free, rs_detect_u32_match, rs_detect_u32_parse, DetectUintData,
};
use crate::detect::{
DetectBufferSetActiveList, DetectHelperBufferMpmRegister, DetectHelperBufferRegister,
DetectHelperGetData, DetectHelperKeywordRegister, DetectSignatureSetAppProto, SCSigTableElmt,
SigMatchAppendSMToList, SIGMATCH_INFO_STICKY_BUFFER, SIGMATCH_NOOPT,
};
use std::os::raw::{c_int, c_void};

#[no_mangle]
pub unsafe extern "C" fn rs_snmp_tx_get_version(tx: &mut SNMPTransaction, version: *mut u32) {
debug_assert!(tx.version != 0, "SNMP version is 0");
*version = tx.version;
static mut G_SNMP_VERSION_KW_ID: c_int = 0;
static mut G_SNMP_VERSION_BUFFER_ID: c_int = 0;
static mut G_SNMP_PDUTYPE_KW_ID: c_int = 0;
static mut G_SNMP_PDUTYPE_BUFFER_ID: c_int = 0;
static mut G_SNMP_USM_BUFFER_ID: c_int = 0;
static mut G_SNMP_COMMUNITY_BUFFER_ID: c_int = 0;

unsafe extern "C" fn snmp_detect_version_setup(
de: *mut c_void, s: *mut c_void, raw: *const libc::c_char,
) -> c_int {
if DetectSignatureSetAppProto(s, ALPROTO_SNMP) != 0 {
return -1;
}
let ctx = rs_detect_u32_parse(raw) as *mut c_void;
if ctx.is_null() {
return -1;
}
if SigMatchAppendSMToList(de, s, G_SNMP_VERSION_KW_ID, ctx, G_SNMP_VERSION_BUFFER_ID).is_null()
{
snmp_detect_version_free(std::ptr::null_mut(), ctx);
return -1;
}
return 0;
}

#[no_mangle]
pub unsafe extern "C" fn rs_snmp_tx_get_community(
tx: &mut SNMPTransaction, buf: *mut *const u8, len: *mut u32,
) {
if let Some(ref c) = tx.community {
*buf = c.as_ptr();
*len = c.len() as u32;
unsafe extern "C" fn snmp_detect_version_match(
_de: *mut c_void, _f: *mut c_void, _flags: u8, _state: *mut c_void, tx: *mut c_void,
_sig: *const c_void, ctx: *const c_void,
) -> c_int {
let tx = cast_pointer!(tx, SNMPTransaction);
let ctx = cast_pointer!(ctx, DetectUintData<u32>);
return rs_detect_u32_match(tx.version, ctx);
}

unsafe extern "C" fn snmp_detect_version_free(_de: *mut c_void, ctx: *mut c_void) {
// Just unbox...
let ctx = cast_pointer!(ctx, DetectUintData<u32>);
rs_detect_u32_free(ctx);
}

unsafe extern "C" fn snmp_detect_pdutype_setup(
de: *mut c_void, s: *mut c_void, raw: *const libc::c_char,
) -> c_int {
if DetectSignatureSetAppProto(s, ALPROTO_SNMP) != 0 {
return -1;
}
let ctx = rs_detect_u32_parse(raw) as *mut c_void;
if ctx.is_null() {
return -1;
}
if SigMatchAppendSMToList(de, s, G_SNMP_PDUTYPE_KW_ID, ctx, G_SNMP_PDUTYPE_BUFFER_ID).is_null()
{
snmp_detect_pdutype_free(std::ptr::null_mut(), ctx);
return -1;
}
return 0;
}

#[no_mangle]
pub unsafe extern "C" 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;
}
None => {
*pdu_type = 0xffffffff;
}
unsafe extern "C" fn snmp_detect_pdutype_match(
_de: *mut c_void, _f: *mut c_void, _flags: u8, _state: *mut c_void, tx: *mut c_void,
_sig: *const c_void, ctx: *const c_void,
) -> c_int {
let tx = cast_pointer!(tx, SNMPTransaction);
let ctx = cast_pointer!(ctx, DetectUintData<u32>);
if let Some(ref info) = tx.info {
let pdu_type = info.pdu_type.0;
return rs_detect_u32_match(pdu_type, ctx);
}
return 0;
}

unsafe extern "C" fn snmp_detect_pdutype_free(_de: *mut c_void, ctx: *mut c_void) {
// Just unbox...
let ctx = cast_pointer!(ctx, DetectUintData<u32>);
rs_detect_u32_free(ctx);
}

pub unsafe extern "C" fn snmp_detect_usm_setup(
de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char,
) -> c_int {
if DetectSignatureSetAppProto(s, ALPROTO_SNMP) != 0 {
return -1;
}
if DetectBufferSetActiveList(de, s, G_SNMP_USM_BUFFER_ID) < 0 {
return -1;
}
return 0;
}

pub unsafe extern "C" fn snmp_detect_usm_get(
tx: *const c_void, _flow_flags: u8, buffer: *mut *const u8, buffer_len: *mut u32,
) -> bool {
let tx = cast_pointer!(tx, SNMPTransaction);
if let Some(ref c) = tx.usm {
*buffer = c.as_ptr();
*buffer_len = c.len() as u32;
return true;
}
return false;
}

pub unsafe extern "C" fn snmp_detect_usm_get_data(
de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8,
tx: *const c_void, list_id: c_int,
) -> *mut c_void {
return DetectHelperGetData(
de,
transforms,
flow,
flow_flags,
tx,
list_id,
snmp_detect_usm_get,
);
}

pub unsafe extern "C" fn snmp_detect_community_setup(
de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char,
) -> c_int {
if DetectSignatureSetAppProto(s, ALPROTO_SNMP) != 0 {
return -1;
}
if DetectBufferSetActiveList(de, s, G_SNMP_COMMUNITY_BUFFER_ID) < 0 {
return -1;
}
return 0;
}

pub unsafe extern "C" fn snmp_detect_community_get(
tx: *const c_void, _flow_flags: u8, buffer: *mut *const u8, buffer_len: *mut u32,
) -> bool {
let tx = cast_pointer!(tx, SNMPTransaction);
if let Some(ref c) = tx.community {
*buffer = c.as_ptr();
*buffer_len = c.len() as u32;
return true;
}
return false;
}

pub unsafe extern "C" fn snmp_detect_community_get_data(
de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8,
tx: *const c_void, list_id: c_int,
) -> *mut c_void {
return DetectHelperGetData(
de,
transforms,
flow,
flow_flags,
tx,
list_id,
snmp_detect_community_get,
);
}
#[no_mangle]
pub unsafe extern "C" fn rs_snmp_tx_get_usm(
tx: &mut SNMPTransaction, buf: *mut *const u8, len: *mut u32,
) {
if let Some(ref c) = tx.usm {
*buf = c.as_ptr();
*len = c.len() as u32;
pub unsafe extern "C" fn ScDetectSNMPRegister() {
let kw = SCSigTableElmt {
name: b"snmp.version\0".as_ptr() as *const libc::c_char,
desc: b"match SNMP version\0".as_ptr() as *const libc::c_char,
url: b"/rules/snmp-keywords.html#snmp-version\0".as_ptr() as *const libc::c_char,
AppLayerTxMatch: Some(snmp_detect_version_match),
Setup: snmp_detect_version_setup,
Free: Some(snmp_detect_version_free),
flags: 0,
};
unsafe {
G_SNMP_VERSION_KW_ID = DetectHelperKeywordRegister(&kw);
G_SNMP_VERSION_BUFFER_ID = DetectHelperBufferRegister(
b"snmp.version\0".as_ptr() as *const libc::c_char,
ALPROTO_SNMP,
true,
true,
);
}

let kw = SCSigTableElmt {
name: b"snmp.pdu_type\0".as_ptr() as *const libc::c_char,
desc: b"match SNMP PDU type\0".as_ptr() as *const libc::c_char,
url: b"/rules/snmp-keywords.html#snmp-pdu-type\0".as_ptr() as *const libc::c_char,
AppLayerTxMatch: Some(snmp_detect_pdutype_match),
Setup: snmp_detect_pdutype_setup,
Free: Some(snmp_detect_pdutype_free),
flags: 0,
};
unsafe {
G_SNMP_PDUTYPE_KW_ID = DetectHelperKeywordRegister(&kw);
G_SNMP_PDUTYPE_BUFFER_ID = DetectHelperBufferRegister(
b"snmp.pdu_type\0".as_ptr() as *const libc::c_char,
ALPROTO_SNMP,
true,
true,
);
}

let kw = SCSigTableElmt {
name: b"snmp.usm\0".as_ptr() as *const libc::c_char,
desc: b"SNMP content modifier to match on the SNMP usm\0".as_ptr() as *const libc::c_char,
url: b"/rules/snmp-keywords.html#snmp-usm\0".as_ptr() as *const libc::c_char,
Setup: snmp_detect_usm_setup,
flags: SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER,
AppLayerTxMatch: None,
Free: None,
};
unsafe {
let _g_snmp_usm_kw_id = DetectHelperKeywordRegister(&kw);
G_SNMP_USM_BUFFER_ID = DetectHelperBufferMpmRegister(
b"snmp.usm\0".as_ptr() as *const libc::c_char,
b"SNMP USM\0".as_ptr() as *const libc::c_char,
ALPROTO_SNMP,
true,
true,
snmp_detect_usm_get_data,
);
}

let kw = SCSigTableElmt {
name: b"snmp.community\0".as_ptr() as *const libc::c_char,
desc: b"SNMP content modifier to match on the SNMP community\0".as_ptr()
as *const libc::c_char,
url: b"/rules/snmp-keywords.html#snmp-community\0".as_ptr() as *const libc::c_char,
Setup: snmp_detect_community_setup,
flags: SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER,
AppLayerTxMatch: None,
Free: None,
};
unsafe {
let _g_snmp_community_kw_id = DetectHelperKeywordRegister(&kw);
G_SNMP_COMMUNITY_BUFFER_ID = DetectHelperBufferMpmRegister(
b"snmp.community\0".as_ptr() as *const libc::c_char,
b"SNMP Community identifier\0".as_ptr() as *const libc::c_char,
ALPROTO_SNMP,
true,
true,
snmp_detect_community_get_data,
);
}
}
2 changes: 1 addition & 1 deletion rust/src/snmp/snmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ pub extern "C" fn rs_snmp_tx_get_alstate_progress(_tx: *mut std::os::raw::c_void
1
}

static mut ALPROTO_SNMP : AppProto = ALPROTO_UNKNOWN;
pub(super) 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> {
Expand Down
Loading