Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic alprotos : make SNMP totally dynamic v10 #12671

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
2 changes: 2 additions & 0 deletions rust/cbindgen.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ include = [
"SCSigTableElmt",
"SCTransformTableElmt",
"DataRepType",
"OutputJsonLogDirection",
"EveJsonTxLoggerRegistrationData",
]

# A list of items to not include in the generated bindings
Expand Down
33 changes: 33 additions & 0 deletions rust/src/applayer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,13 +472,46 @@ pub type ApplyTxConfigFn = unsafe extern "C" fn (*mut c_void, *mut c_void, c_int
pub type GetFrameIdByName = unsafe extern "C" fn(*const c_char) -> c_int;
pub type GetFrameNameById = unsafe extern "C" fn(u8) -> *const c_char;

#[repr(C)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[allow(non_camel_case_types)]
pub enum OutputJsonLogDirection {
LOG_DIR_PACKET = 0,
LOG_DIR_FLOW = 1,
LOG_DIR_FLOW_TOCLIENT = 2,
LOG_DIR_FLOW_TOSERVER = 3,
}

#[repr(C)]
#[allow(non_snake_case)]
pub struct EveJsonTxLoggerRegistrationData {
pub confname: *const c_char,
pub logname: *const c_char,
pub alproto: AppProto,
pub dir: u8,
// EveJsonSimpleTxLogFunc, cannot use JsonBuilder as it is not #[repr(C)]
pub LogTx: unsafe extern "C" fn(*const c_void, *mut c_void) -> bool,
}

// Defined in output.h
/// cbindgen:ignore
extern {
pub fn OutputPreRegisterLogger(reg_data: EveJsonTxLoggerRegistrationData) -> c_int;
}

// Defined in detect-engine-register.h
/// cbindgen:ignore
extern {
pub fn SigTablePreRegister(cb: unsafe extern "C" fn ());
}

// Defined in app-layer-register.h
/// cbindgen:ignore
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);
pub fn AppLayerRegisterParser(parser: *const RustParser, alproto: AppProto) -> c_int;
pub fn AppProtoNewProtoFromString(name: *const c_char) -> AppProto;
}


Expand Down
16 changes: 8 additions & 8 deletions rust/src/snmp/detect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ unsafe extern "C" fn snmp_detect_pdutype_free(_de: *mut c_void, ctx: *mut c_void
rs_detect_u32_free(ctx);
}

pub unsafe extern "C" fn snmp_detect_usm_setup(
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 {
Expand All @@ -117,7 +117,7 @@ pub unsafe extern "C" fn snmp_detect_usm_setup(
return 0;
}

pub unsafe extern "C" fn snmp_detect_usm_get(
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);
Expand All @@ -129,7 +129,7 @@ pub unsafe extern "C" fn snmp_detect_usm_get(
return false;
}

pub unsafe extern "C" fn snmp_detect_usm_get_data(
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 {
Expand All @@ -144,7 +144,7 @@ pub unsafe extern "C" fn snmp_detect_usm_get_data(
);
}

pub unsafe extern "C" fn snmp_detect_community_setup(
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 {
Expand All @@ -156,7 +156,7 @@ pub unsafe extern "C" fn snmp_detect_community_setup(
return 0;
}

pub unsafe extern "C" fn snmp_detect_community_get(
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);
Expand All @@ -168,7 +168,7 @@ pub unsafe extern "C" fn snmp_detect_community_get(
return false;
}

pub unsafe extern "C" fn snmp_detect_community_get_data(
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 {
Expand All @@ -182,8 +182,8 @@ pub unsafe extern "C" fn snmp_detect_community_get_data(
snmp_detect_community_get,
);
}
#[no_mangle]
pub unsafe extern "C" fn SCDetectSNMPRegister() {

pub(super) unsafe extern "C" fn detect_snmp_register() {
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,
Expand Down
19 changes: 11 additions & 8 deletions rust/src/snmp/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<str> {
fn str_of_pdu_type(t: &PduType) -> Cow<str> {
match t {
&PduType::GetRequest => Cow::Borrowed("get_request"),
&PduType::GetNextRequest => Cow::Borrowed("get_next_request"),
Expand All @@ -37,8 +37,7 @@ fn str_of_pdu_type(t:&PduType) -> Cow<str> {
}
}

fn snmp_log_response(jsb: &mut JsonBuilder, tx: &mut SNMPTransaction) -> Result<(), JsonError>
{
fn snmp_log_response(jsb: &mut JsonBuilder, tx: &SNMPTransaction) -> Result<(), JsonError> {
jsb.open_object("snmp")?;
jsb.set_uint("version", tx.version as u64)?;
if tx.encrypted {
Expand All @@ -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() {
Expand All @@ -76,8 +77,10 @@ fn snmp_log_response(jsb: &mut JsonBuilder, tx: &mut SNMPTransaction) -> Result<
return Ok(());
}

#[no_mangle]
pub extern "C" fn rs_snmp_log_json_response(tx: &mut SNMPTransaction, jsb: &mut JsonBuilder) -> bool
{
pub(super) unsafe extern "C" fn rs_snmp_log_json_response(
tx: *const std::os::raw::c_void, jsb: *mut std::os::raw::c_void,
) -> bool {
let tx = cast_pointer!(tx, SNMPTransaction);
let jsb = cast_pointer!(jsb, JsonBuilder);
snmp_log_response(jsb, tx).is_ok()
}
60 changes: 31 additions & 29 deletions rust/src/snmp/snmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ use crate::flow::Flow;
use crate::snmp::snmp_parser::*;
use crate::core::{self, *};
use crate::applayer::{self, *};
use super::log::rs_snmp_log_json_response;
use super::detect::detect_snmp_register;
use std;
use std::ffi::CString;

Expand All @@ -33,18 +35,18 @@ use nom7::error::{ErrorKind, make_error};
use suricata_sys::sys::AppProto;

#[derive(AppLayerEvent)]
pub enum SNMPEvent {
enum SNMPEvent {
MalformedData,
UnknownSecurityModel,
VersionMismatch,
}

#[derive(Default)]
pub struct SNMPState<'a> {
struct SNMPState<'a> {
state_data: AppLayerStateData,

/// SNMP protocol version
pub version: u32,
version: u32,

/// List of transactions for this session
transactions: Vec<SNMPTransaction<'a>>,
Expand All @@ -53,7 +55,7 @@ pub struct SNMPState<'a> {
tx_id: u64,
}

pub struct SNMPPduInfo<'a> {
pub(super) struct SNMPPduInfo<'a> {
pub pdu_type: PduType,

pub err: ErrorStatus,
Expand All @@ -63,7 +65,7 @@ pub struct SNMPPduInfo<'a> {
pub vars: Vec<Oid<'a>>,
}

pub struct SNMPTransaction<'a> {
pub(super) struct SNMPTransaction<'a> {
/// PDU version
pub version: u32,

Expand Down Expand Up @@ -92,7 +94,7 @@ impl Transaction for SNMPTransaction<'_> {
}

impl<'a> SNMPState<'a> {
pub fn new() -> SNMPState<'a> {
fn new() -> SNMPState<'a> {
Default::default()
}
}
Expand Down Expand Up @@ -238,7 +240,7 @@ impl<'a> SNMPState<'a> {
}

impl<'a> SNMPTransaction<'a> {
pub fn new(direction: Direction, version: u32, id: u64) -> SNMPTransaction<'a> {
fn new(direction: Direction, version: u32, id: u64) -> SNMPTransaction<'a> {
SNMPTransaction {
version,
info: None,
Expand All @@ -252,23 +254,20 @@ 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 {
extern "C" 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 _;
}

/// Params:
/// - state: *mut SNMPState as void pointer
#[no_mangle]
pub extern "C" fn rs_snmp_state_free(state: *mut std::os::raw::c_void) {
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) };
snmp_state.free();
}

#[no_mangle]
pub unsafe extern "C" fn rs_snmp_parse_request(_flow: *const Flow,
unsafe extern "C" fn rs_snmp_parse_request(_flow: *const Flow,
state: *mut std::os::raw::c_void,
_pstate: *mut std::os::raw::c_void,
stream_slice: StreamSlice,
Expand All @@ -278,8 +277,7 @@ pub unsafe extern "C" fn rs_snmp_parse_request(_flow: *const Flow,
state.parse(stream_slice.as_slice(), Direction::ToServer).into()
}

#[no_mangle]
pub unsafe extern "C" fn rs_snmp_parse_response(_flow: *const Flow,
unsafe extern "C" fn rs_snmp_parse_response(_flow: *const Flow,
state: *mut std::os::raw::c_void,
_pstate: *mut std::os::raw::c_void,
stream_slice: StreamSlice,
Expand All @@ -289,8 +287,7 @@ pub unsafe extern "C" fn rs_snmp_parse_response(_flow: *const Flow,
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,
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
{
Expand All @@ -301,24 +298,21 @@ pub unsafe extern "C" fn rs_snmp_state_get_tx(state: *mut std::os::raw::c_void,
}
}

#[no_mangle]
pub unsafe extern "C" fn rs_snmp_state_get_tx_count(state: *mut std::os::raw::c_void)
unsafe extern "C" 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,
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);
state.free_tx(tx_id);
}

#[no_mangle]
pub extern "C" fn rs_snmp_tx_get_alstate_progress(_tx: *mut std::os::raw::c_void,
extern "C" fn rs_snmp_tx_get_alstate_progress(_tx: *mut std::os::raw::c_void,
_direction: u8)
-> std::os::raw::c_int
{
Expand Down Expand Up @@ -355,7 +349,7 @@ fn parse_pdu_envelope_version(i:&[u8]) -> IResult<&[u8],u32> {
}

#[no_mangle]
pub unsafe extern "C" fn rs_snmp_probing_parser(_flow: *const Flow,
unsafe extern "C" fn rs_snmp_probing_parser(_flow: *const Flow,
_direction: u8,
input:*const u8,
input_len: u32,
Expand Down Expand Up @@ -413,20 +407,28 @@ pub unsafe extern "C" fn rs_register_snmp_parser() {
get_frame_name_by_id: None,
};
let ip_proto_str = CString::new("udp").unwrap();
ALPROTO_SNMP = AppProtoNewProtoFromString(PARSER_NAME.as_ptr() as *const std::os::raw::c_char);
let reg_data = EveJsonTxLoggerRegistrationData {
confname: b"eve-log.snmp\0".as_ptr() as *const std::os::raw::c_char,
logname: b"JsonSNMPLog\0".as_ptr() as *const std::os::raw::c_char,
alproto: ALPROTO_SNMP,
dir: OutputJsonLogDirection::LOG_DIR_PACKET as u8,
LogTx: rs_snmp_log_json_response,
};
OutputPreRegisterLogger(reg_data);
SigTablePreRegister(detect_snmp_register);
if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
// port 161
let alproto = AppLayerRegisterProtocolDetection(&parser, 1);
// store the allocated ID for the probe function
ALPROTO_SNMP = alproto;
_ = AppLayerRegisterProtocolDetection(&parser, 1);
if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
let _ = AppLayerRegisterParser(&parser, alproto);
let _ = AppLayerRegisterParser(&parser, ALPROTO_SNMP);
}
// port 162
let default_port_traps = CString::new("162").unwrap();
parser.default_port = default_port_traps.as_ptr();
let _ = AppLayerRegisterProtocolDetection(&parser, 1);
if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
let _ = AppLayerRegisterParser(&parser, alproto);
let _ = AppLayerRegisterParser(&parser, ALPROTO_SNMP);
}
AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_SNMP);
} else {
Expand Down
Loading
Loading