Skip to content

Commit

Permalink
detect/snmp: move keywords to rust
Browse files Browse the repository at this point in the history
Ticket: 4863

On the way, convert unit test DetectSNMPCommunityTest to a SV test.

And also, make snmp.pdu_type use a generic uint32 for detection,
allowing operators, instead of just equality.
  • Loading branch information
catenacyber committed May 7, 2024
1 parent 9781f20 commit cf0f30c
Show file tree
Hide file tree
Showing 16 changed files with 243 additions and 834 deletions.
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
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 <[email protected]>

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
10 changes: 0 additions & 10 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -294,10 +294,6 @@ noinst_HEADERS = \
detect-smb-ntlmssp.h \
detect-smb-share.h \
detect-smb-version.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 \
Expand Down Expand Up @@ -903,10 +899,6 @@ libsuricata_c_a_SOURCES = \
detect-smb-ntlmssp.c \
detect-smb-share.c \
detect-smb-version.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 \
Expand Down Expand Up @@ -1229,8 +1221,6 @@ EXTRA_DIST = \
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 \
Expand Down
10 changes: 2 additions & 8 deletions src/detect-engine-register.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,6 @@
#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"
Expand Down Expand Up @@ -703,10 +699,6 @@ void SigTableSetup(void)
DetectDHCPLeaseTimeRegister();
DetectDHCPRebindingTimeRegister();
DetectDHCPRenewalTimeRegister();
DetectSNMPUsmRegister();
DetectSNMPVersionRegister();
DetectSNMPCommunityRegister();
DetectSNMPPduTypeRegister();
DetectMQTTTypeRegister();
DetectMQTTFlagsRegister();
DetectMQTTQosRegister();
Expand Down Expand Up @@ -751,6 +743,8 @@ void SigTableSetup(void)

DetectFileHandlerRegister();

ScDetectSNMPRegister();

/* close keyword registration */
DetectBufferTypeCloseRegistration();
}
Expand Down
4 changes: 0 additions & 4 deletions src/detect-engine-register.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,10 +293,6 @@ enum DetectKeywordId {
DETECT_AL_DHCP_LEASETIME,
DETECT_AL_DHCP_REBINDING_TIME,
DETECT_AL_DHCP_RENEWAL_TIME,
DETECT_AL_SNMP_USM,
DETECT_AL_SNMP_VERSION,
DETECT_AL_SNMP_COMMUNITY,
DETECT_AL_SNMP_PDU_TYPE,
DETECT_AL_MQTT_TYPE,
DETECT_AL_MQTT_FLAGS,
DETECT_AL_MQTT_QOS,
Expand Down
Loading

0 comments on commit cf0f30c

Please sign in to comment.