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 v3 #12408

Closed
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
37 changes: 37 additions & 0 deletions rust/src/applayer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,12 +472,49 @@ 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;

// Also defined in output-json.h
/// cbindgen:ignore
#[repr(u8)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[allow(non_camel_case_types)]
pub enum OutputJsonLogDirection {
LOG_DIR_PACKET = 0,
LOG_DIR_FLOW = 1,
}

// Also defined in output.h
// canot use JsonBuilder as it is not #[repr(C)]
pub type EveJsonSimpleTxLogFunc = unsafe extern "C" fn(*const c_void, *mut c_void) -> bool;

// Also defined in output.h
#[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,
pub LogTx: EveJsonSimpleTxLogFunc,
}

// 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 AppProtoNewProtoFromString(name: *const c_char) -> AppProto;
}

#[allow(non_snake_case)]
Expand Down
18 changes: 11 additions & 7 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 @@ -77,7 +78,10 @@ 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 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()
}
20 changes: 15 additions & 5 deletions rust/src/snmp/snmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
use crate::snmp::snmp_parser::*;
use crate::core::{self, *};
use crate::applayer::{self, *};
use super::log::rs_snmp_log_json_response;
use super::detect::ScDetectSNMPRegister;
use std;
use std::ffi::CString;

Expand Down Expand Up @@ -410,20 +412,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(ScDetectSNMPRegister);
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
20 changes: 19 additions & 1 deletion src/app-layer-detect-proto.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,14 @@ typedef struct AppLayerProtoDetectCtx_ {
* ipproto. It should be allocated to contain ALPROTO_MAX
* protocols. */
const char **alproto_names;
size_t alproto_names_len;

/* Protocol expectations, like ftp-data on tcp.
* It should be allocated to contain ALPROTO_MAX
* app-layer protocols. For each protocol, an iptype
* is referenced (or 0 if there is no expectation). */
uint8_t *expectation_proto;
size_t expectation_proto_len;
} AppLayerProtoDetectCtx;

typedef struct AppLayerProtoDetectAliases_ {
Expand Down Expand Up @@ -1729,11 +1731,13 @@ int AppLayerProtoDetectSetup(void)
if (unlikely(alpd_ctx.alproto_names == NULL)) {
FatalError("Unable to alloc alproto_names.");
}
alpd_ctx.alproto_names_len = g_alproto_max;
// to realloc when dynamic protos are added
alpd_ctx.expectation_proto = SCCalloc(g_alproto_max, sizeof(uint8_t));
if (unlikely(alpd_ctx.expectation_proto == NULL)) {
FatalError("Unable to alloc expectation_proto.");
}
alpd_ctx.expectation_proto_len = g_alproto_max;
AppLayerExpectationSetup();

SCReturnInt(0);
Expand Down Expand Up @@ -1767,8 +1771,10 @@ int AppLayerProtoDetectDeSetup(void)

SCFree(alpd_ctx.alproto_names);
alpd_ctx.alproto_names = NULL;
alpd_ctx.alproto_names_len = 0;
SCFree(alpd_ctx.expectation_proto);
alpd_ctx.expectation_proto = NULL;
alpd_ctx.expectation_proto_len = 0;

SpmDestroyGlobalThreadCtx(alpd_ctx.spm_global_thread_ctx);

Expand All @@ -1783,7 +1789,16 @@ void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_n
{
SCEnter();

// should have just been realloced when dynamic protos is added
if (alpd_ctx.alproto_names_len <= alproto && alproto < g_alproto_max) {
void *tmp = SCRealloc(alpd_ctx.alproto_names, sizeof(char *) * g_alproto_max);
if (unlikely(tmp == NULL)) {
FatalError("Unable to realloc alproto_names.");
}
alpd_ctx.alproto_names = tmp;
memset(&alpd_ctx.alproto_names[alpd_ctx.alproto_names_len], 0,
sizeof(char *) * (g_alproto_max - alpd_ctx.alproto_names_len));
alpd_ctx.alproto_names_len = g_alproto_max;
}
if (alpd_ctx.alproto_names[alproto] == NULL)
alpd_ctx.alproto_names[alproto] = alproto_name;

Expand Down Expand Up @@ -2136,6 +2151,9 @@ void AppLayerProtoDetectSupportedAppProtocols(AppProto *alprotos)
static void AppLayerProtoDetectPEGetIpprotos(AppProto alproto,
uint8_t *ipprotos)
{
if (alproto >= alpd_ctx.expectation_proto_len) {
return;
}
if (alpd_ctx.expectation_proto[alproto] == IPPROTO_TCP) {
ipprotos[IPPROTO_TCP / 8] |= 1 << (IPPROTO_TCP % 8);
}
Expand Down
17 changes: 16 additions & 1 deletion src/app-layer-parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ typedef struct AppLayerParserProtoCtx_

typedef struct AppLayerParserCtx_ {
AppLayerParserProtoCtx (*ctxs)[FLOW_PROTO_MAX];
size_t ctxs_len;
} AppLayerParserCtx;

struct AppLayerParserState_ {
Expand Down Expand Up @@ -254,6 +255,7 @@ int AppLayerParserSetup(void)
if (unlikely(alp_ctx.ctxs == NULL)) {
FatalError("Unable to alloc alp_ctx.ctxs.");
}
alp_ctx.ctxs_len = g_alproto_max;
SCReturnInt(0);
}

Expand Down Expand Up @@ -426,6 +428,20 @@ void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto,
{
SCEnter();

if (alp_ctx.ctxs_len <= alproto && alproto < g_alproto_max) {
// Realloc now as AppLayerParserRegisterStateFuncs is called first
void *tmp = SCRealloc(
alp_ctx.ctxs, sizeof(AppLayerParserProtoCtx[FLOW_PROTO_MAX]) * g_alproto_max);
if (unlikely(tmp == NULL)) {
FatalError("Unable to realloc alp_ctx.ctxs.");
}
alp_ctx.ctxs = tmp;
memset(&alp_ctx.ctxs[alp_ctx.ctxs_len], 0,
sizeof(AppLayerParserProtoCtx[FLOW_PROTO_MAX]) *
(g_alproto_max - alp_ctx.ctxs_len));
alp_ctx.ctxs_len = g_alproto_max;
}

alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateAlloc = StateAlloc;
alp_ctx.ctxs[alproto][FlowGetProtoMapping(ipproto)].StateFree = StateFree;

Expand Down Expand Up @@ -1683,7 +1699,6 @@ static void ValidateParserProto(AppProto alproto, uint8_t ipproto)
}
#undef BOTH_SET
#undef BOTH_SET_OR_BOTH_UNSET
#undef THREE_SET_OR_THREE_UNSET
#undef THREE_SET

static void ValidateParser(AppProto alproto)
Expand Down
6 changes: 6 additions & 0 deletions src/app-layer-protos.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ AppProto StringToAppProto(const char *proto_name)
return ALPROTO_UNKNOWN;
}

AppProto AppProtoNewProtoFromString(const char *proto_name)
{
AppProtoRegisterProtoString(g_alproto_max, proto_name);
return g_alproto_max - 1;
}

void AppProtoRegisterProtoString(AppProto alproto, const char *proto_name)
{
if (alproto < ALPROTO_MAX_STATIC) {
Expand Down
4 changes: 3 additions & 1 deletion src/app-layer-protos.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ enum AppProtoEnum {
ALPROTO_KRB5,
ALPROTO_QUIC,
ALPROTO_DHCP,
ALPROTO_SNMP,
ALPROTO_SIP,
ALPROTO_RFB,
ALPROTO_MQTT,
Expand All @@ -78,6 +77,7 @@ enum AppProtoEnum {
/* keep last */
ALPROTO_MAX_STATIC,
// After this ALPROTO_MAX_STATIC can come dynamic alproto ids
// For example, ALPROTO_SNMP is now dynamic
};
// NOTE: if ALPROTO's get >= 256, update SignatureNonPrefilterStore

Expand Down Expand Up @@ -175,6 +175,8 @@ const char *AppProtoToString(AppProto alproto);
*/
AppProto StringToAppProto(const char *proto_name);

AppProto AppProtoNewProtoFromString(const char *proto_name);

void AppProtoRegisterProtoString(AppProto alproto, const char *proto_name);

#endif /* SURICATA_APP_LAYER_PROTOS_H */
1 change: 0 additions & 1 deletion src/app-layer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1055,7 +1055,6 @@ static void AppLayerNamesSetup(void)
AppProtoRegisterProtoString(ALPROTO_KRB5, "krb5");
AppProtoRegisterProtoString(ALPROTO_QUIC, "quic");
AppProtoRegisterProtoString(ALPROTO_DHCP, "dhcp");
AppProtoRegisterProtoString(ALPROTO_SNMP, "snmp");
AppProtoRegisterProtoString(ALPROTO_SIP, "sip");
AppProtoRegisterProtoString(ALPROTO_RFB, "rfb");
AppProtoRegisterProtoString(ALPROTO_MQTT, "mqtt");
Expand Down
1 change: 0 additions & 1 deletion src/detect-engine-register.c
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,6 @@ void SigTableSetup(void)
DetectVlanIdRegister();
DetectVlanLayersRegister();

ScDetectSNMPRegister();
ScDetectDHCPRegister();
ScDetectWebsocketRegister();
ScDetectEnipRegister();
Expand Down
4 changes: 3 additions & 1 deletion src/detect-parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ void DetectFileRegisterProto(
al_protocols[i].direction = direction;
al_protocols[i].to_client_progress = to_client_progress;
al_protocols[i].to_server_progress = to_server_progress;
al_protocols[i + 1].alproto = ALPROTO_UNKNOWN;
if (i + 1 < ALPROTO_WITHFILES_MAX) {
al_protocols[i + 1].alproto = ALPROTO_UNKNOWN;
}
}

void DetectFileRegisterFileProtocols(DetectFileHandlerTableElmt *reg)
Expand Down
20 changes: 11 additions & 9 deletions src/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -885,8 +885,6 @@ void OutputRegisterRootLoggers(void)
ALPROTO_KRB5, (EveJsonSimpleTxLogFunc)rs_krb5_log_json_response, NULL);
RegisterSimpleJsonApplayerLogger(ALPROTO_QUIC, rs_quic_to_json, NULL);
// ALPROTO_DHCP TODO missing
RegisterSimpleJsonApplayerLogger(
ALPROTO_SNMP, (EveJsonSimpleTxLogFunc)rs_snmp_log_json_response, NULL);
RegisterSimpleJsonApplayerLogger(ALPROTO_SIP, (EveJsonSimpleTxLogFunc)rs_sip_log_json, NULL);
RegisterSimpleJsonApplayerLogger(ALPROTO_RFB, rs_rfb_logger_log, NULL);
RegisterSimpleJsonApplayerLogger(ALPROTO_MQTT, JsonMQTTAddMetadata, NULL);
Expand Down Expand Up @@ -975,6 +973,15 @@ int OutputPreRegisterLogger(EveJsonTxLoggerRegistrationData reg_data)
return 0;
}

static TxLogger JsonLoggerFromDir(uint8_t dir)
{
if (dir == LOG_DIR_PACKET) {
return JsonGenericDirPacketLogger;
}
BUG_ON(dir != LOG_DIR_FLOW);
return JsonGenericDirFlowLogger;
}

/**
* \brief Register all non-root logging modules.
*/
Expand Down Expand Up @@ -1075,12 +1082,7 @@ void OutputRegisterLoggers(void)
SCLogDebug("quic json logger registered.");
/* DHCP JSON logger. */
JsonDHCPLogRegister();
/* SNMP JSON logger. */
OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonSNMPLog", "eve-log.snmp",
OutputJsonLogInitSub, ALPROTO_SNMP, JsonGenericDirPacketLogger, JsonLogThreadInit,
JsonLogThreadDeinit);

SCLogDebug("SNMP JSON logger registered.");
/* SIP JSON logger. */
OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonSIPLog", "eve-log.sip",
OutputJsonLogInitSub, ALPROTO_SIP, JsonGenericDirPacketLogger, JsonLogThreadInit,
Expand Down Expand Up @@ -1135,8 +1137,8 @@ void OutputRegisterLoggers(void)
for (size_t i = 0; i < preregistered_loggers_nb; i++) {
OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", preregistered_loggers[i].logname,
preregistered_loggers[i].confname, OutputJsonLogInitSub,
preregistered_loggers[i].alproto, JsonGenericDirFlowLogger, JsonLogThreadInit,
JsonLogThreadDeinit);
preregistered_loggers[i].alproto, JsonLoggerFromDir(preregistered_loggers[i].dir),
JsonLogThreadInit, JsonLogThreadDeinit);
SCLogDebug(
"%s JSON logger registered.", AppProtoToString(preregistered_loggers[i].alproto));
RegisterSimpleJsonApplayerLogger(
Expand Down
1 change: 1 addition & 0 deletions src/output.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ typedef struct EveJsonTxLoggerRegistrationData {
const char *confname;
const char *logname;
AppProto alproto;
uint8_t dir;
EveJsonSimpleTxLogFunc LogTx;
} EveJsonTxLoggerRegistrationData;

Expand Down
3 changes: 2 additions & 1 deletion src/suricata-plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ typedef struct SCCapturePlugin_ {
int SCPluginRegisterCapture(SCCapturePlugin *);

// Every change in the API used by plugins should change this number
#define SC_PLUGIN_API_VERSION 8
#define SC_PLUGIN_API_VERSION 0x801

typedef struct SCAppLayerPlugin_ {
// versioning to check suricata/plugin API compatibility
Expand All @@ -63,6 +63,7 @@ typedef struct SCAppLayerPlugin_ {
void (*KeywordsRegister)(void);
char *logname;
char *confname;
uint8_t dir;
bool (*Logger)(void *tx, void *jb);
} SCAppLayerPlugin;

Expand Down
Loading
Loading