detect/mqtt: move keywords to rust

Ticket: 4863

On the way, convert some keywords to use the first-class integer
support.
And helpers for pure rust the support for multi-buffer.

Move the C unit tests about keyword mqtt.protocol_version
to unit tests for generic integer parsing, and test version 5
instead of testing twice version 3.

Also iterate all tx's messages for reason code as is done for other
keywords.

And allow detection on empty topics.
pull/11510/head
Philippe Antoine 1 year ago committed by Victor Julien
parent f4e7d1e217
commit 0a1062fad2

@ -46,10 +46,13 @@ Valid values are :
where ``UNASSIGNED`` refers to message type code 0.
mqtt.type uses an :ref:`unsigned 8-bits integer <rules-integer-keywords>`.
Examples::
mqtt.type:CONNECT;
mqtt.type:PUBLISH;
mqtt.type:2;
mqtt.flags
@ -57,6 +60,8 @@ mqtt.flags
Match on a combination of MQTT header flags, separated by commas (``,``). Flags may be prefixed by ``!`` to indicate negation, i.e. a flag prefixed by ``!`` must `not` be set to match.
mqtt.flags uses an :ref:`unsigned 8-bits integer <rules-integer-keywords>`
Valid flags are:
* ``dup`` (duplicate message)
@ -89,6 +94,8 @@ mqtt.reason_code
Match on the numeric value of the reason code that is used in MQTT 5.0 for some message types. Please refer to the specification for the meaning of these values, which are often specific to the message type in question.
mqtt.reason_code uses an :ref:`unsigned 8-bits integer <rules-integer-keywords>`.
Examples::
# match on attempts to unsubscribe from a non-subscribed topic
@ -137,6 +144,8 @@ mqtt.connect.flags
Match on a combination of MQTT CONNECT flags, separated by commas (``,``). Flags may be prefixed by ``!`` to indicate negation, i.e. a flag prefixed by ``!`` must `not` be set to match.
mqtt.connect.flags uses an :ref:`unsigned 8-bits integer <rules-integer-keywords>`
Valid flags are:
* ``username`` (message contains a username)

@ -104,6 +104,30 @@ extern {
pub fn SigMatchAppendSMToList(
de: *mut c_void, s: *mut c_void, kwid: c_int, ctx: *const c_void, bufid: c_int,
) -> *mut c_void;
// in detect-engine-helper.h
pub fn DetectHelperGetMultiData(
de: *mut c_void,
transforms: *const c_void,
flow: *const c_void,
flow_flags: u8,
tx: *const c_void,
list_id: c_int,
local_id: u32,
get_buf: unsafe extern "C" fn(*const c_void, u8, u32, *mut *const u8, *mut u32) -> bool,
) -> *mut c_void;
pub fn DetectHelperMultiBufferMpmRegister(
name: *const libc::c_char, desc: *const libc::c_char, alproto: AppProto, toclient: bool,
toserver: bool,
get_multi_data: unsafe extern "C" fn(
*mut c_void,
*const c_void,
*const c_void,
u8,
*const c_void,
i32,
u32,
) -> *mut c_void,
) -> c_int;
}
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]

@ -581,4 +581,22 @@ mod tests {
let (_, val) = detect_parse_uint::<u32>("> 3MB").unwrap();
assert_eq!(val.arg1, 3 * 1024 * 1024);
}
#[test]
fn test_parse_uint_like_mqtt_protocol_version() {
let (_, val) = detect_parse_uint::<u8>("3").unwrap();
assert_eq!(val.mode, DetectUintMode::DetectUintModeEqual);
assert_eq!(val.arg1, 3);
let (_, val) = detect_parse_uint::<u8>("5").unwrap();
assert_eq!(val.mode, DetectUintMode::DetectUintModeEqual);
assert_eq!(val.arg1, 5);
let (_, val) = detect_parse_uint::<u8>(">3").unwrap();
assert_eq!(val.mode, DetectUintMode::DetectUintModeGt);
assert_eq!(val.arg1, 3);
let (_, val) = detect_parse_uint::<u8>("<44").unwrap();
assert_eq!(val.mode, DetectUintMode::DetectUintModeLt);
assert_eq!(val.arg1, 44);
assert!(detect_parse_uint::<u8>("").is_err());
assert!(detect_parse_uint::<u8>("<444").is_err());
}
}

File diff suppressed because it is too large Load Diff

@ -40,7 +40,7 @@ static mut MAX_MSG_LEN: u32 = 1048576;
static mut MQTT_MAX_TX: usize = 1024;
static mut ALPROTO_MQTT: AppProto = ALPROTO_UNKNOWN;
pub(super) static mut ALPROTO_MQTT: AppProto = ALPROTO_UNKNOWN;
#[derive(AppLayerFrameType)]
pub enum MQTTFrameType {
@ -708,9 +708,8 @@ pub unsafe extern "C" fn rs_mqtt_state_get_tx_count(state: *mut std::os::raw::c_
#[no_mangle]
pub unsafe extern "C" fn rs_mqtt_tx_is_toclient(
tx: *const std::os::raw::c_void,
tx: &MQTTTransaction,
) -> std::os::raw::c_int {
let tx = cast_pointer!(tx, MQTTTransaction);
if tx.toclient {
return 1;
}

@ -20,6 +20,7 @@
use crate::mqtt::mqtt_property::*;
use crate::mqtt::parser::*;
use std::fmt;
use suricata_derive::EnumStringU8;
#[derive(Debug)]
pub struct MQTTMessage {
@ -52,7 +53,7 @@ pub enum MQTTOperation {
}
#[repr(u8)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, FromPrimitive, Debug)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, FromPrimitive, Debug, EnumStringU8)]
pub enum MQTTTypeCode {
UNASSIGNED = 0,
CONNECT = 1,
@ -84,32 +85,6 @@ impl fmt::Display for MQTTTypeCode {
}
}
impl std::str::FromStr for MQTTTypeCode {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let su = s.to_uppercase();
let su_slice: &str = &su;
match su_slice {
"CONNECT" => Ok(MQTTTypeCode::CONNECT),
"CONNACK" => Ok(MQTTTypeCode::CONNACK),
"PUBLISH" => Ok(MQTTTypeCode::PUBLISH),
"PUBACK" => Ok(MQTTTypeCode::PUBACK),
"PUBREC" => Ok(MQTTTypeCode::PUBREC),
"PUBREL" => Ok(MQTTTypeCode::PUBREL),
"PUBCOMP" => Ok(MQTTTypeCode::PUBCOMP),
"SUBSCRIBE" => Ok(MQTTTypeCode::SUBSCRIBE),
"SUBACK" => Ok(MQTTTypeCode::SUBACK),
"UNSUBSCRIBE" => Ok(MQTTTypeCode::UNSUBSCRIBE),
"UNSUBACK" => Ok(MQTTTypeCode::UNSUBACK),
"PINGREQ" => Ok(MQTTTypeCode::PINGREQ),
"PINGRESP" => Ok(MQTTTypeCode::PINGRESP),
"DISCONNECT" => Ok(MQTTTypeCode::DISCONNECT),
"AUTH" => Ok(MQTTTypeCode::AUTH),
_ => Err(format!("'{}' is not a valid value for MQTTTypeCode", s)),
}
}
}
#[derive(Debug)]
pub struct MQTTConnectData {
pub protocol_string: String,

@ -241,23 +241,6 @@ noinst_HEADERS = \
detect-quic-version.h \
detect-quic-cyu-hash.h \
detect-quic-cyu-string.h \
detect-mqtt-connack-sessionpresent.h \
detect-mqtt-connect-clientid.h \
detect-mqtt-connect-flags.h \
detect-mqtt-connect-password.h \
detect-mqtt-connect-protocol-string.h \
detect-mqtt-connect-username.h \
detect-mqtt-connect-willmessage.h \
detect-mqtt-connect-willtopic.h \
detect-mqtt-flags.h \
detect-mqtt-protocol-version.h \
detect-mqtt-publish-message.h \
detect-mqtt-publish-topic.h \
detect-mqtt-qos.h \
detect-mqtt-reason-code.h \
detect-mqtt-subscribe-topic.h \
detect-mqtt-type.h \
detect-mqtt-unsubscribe-topic.h \
detect-msg.h \
detect-nfs-procedure.h \
detect-nfs-version.h \
@ -840,23 +823,6 @@ libsuricata_c_a_SOURCES = \
detect-quic-version.c \
detect-quic-cyu-hash.c \
detect-quic-cyu-string.c \
detect-mqtt-connack-sessionpresent.c \
detect-mqtt-connect-clientid.c \
detect-mqtt-connect-flags.c \
detect-mqtt-connect-password.c \
detect-mqtt-connect-protocol-string.c \
detect-mqtt-connect-username.c \
detect-mqtt-connect-willmessage.c \
detect-mqtt-connect-willtopic.c \
detect-mqtt-flags.c \
detect-mqtt-protocol-version.c \
detect-mqtt-publish-message.c \
detect-mqtt-publish-topic.c \
detect-mqtt-qos.c \
detect-mqtt-reason-code.c \
detect-mqtt-subscribe-topic.c \
detect-mqtt-type.c \
detect-mqtt-unsubscribe-topic.c \
detect-msg.c \
detect-nfs-procedure.c \
detect-nfs-version.c \

@ -213,23 +213,6 @@
#include "detect-rfb-name.h"
#include "detect-target.h"
#include "detect-template-rust-buffer.h"
#include "detect-mqtt-type.h"
#include "detect-mqtt-flags.h"
#include "detect-mqtt-qos.h"
#include "detect-mqtt-protocol-version.h"
#include "detect-mqtt-reason-code.h"
#include "detect-mqtt-connect-flags.h"
#include "detect-mqtt-connect-clientid.h"
#include "detect-mqtt-connect-username.h"
#include "detect-mqtt-connect-password.h"
#include "detect-mqtt-connect-protocol-string.h"
#include "detect-mqtt-connect-willtopic.h"
#include "detect-mqtt-connect-willmessage.h"
#include "detect-mqtt-connack-sessionpresent.h"
#include "detect-mqtt-publish-topic.h"
#include "detect-mqtt-publish-message.h"
#include "detect-mqtt-subscribe-topic.h"
#include "detect-mqtt-unsubscribe-topic.h"
#include "detect-quic-sni.h"
#include "detect-quic-ua.h"
#include "detect-quic-version.h"
@ -694,23 +677,6 @@ void SigTableSetup(void)
DetectRfbNameRegister();
DetectTargetRegister();
DetectTemplateRustBufferRegister();
DetectMQTTTypeRegister();
DetectMQTTFlagsRegister();
DetectMQTTQosRegister();
DetectMQTTProtocolVersionRegister();
DetectMQTTReasonCodeRegister();
DetectMQTTConnectFlagsRegister();
DetectMQTTConnectClientIDRegister();
DetectMQTTConnectUsernameRegister();
DetectMQTTConnectPasswordRegister();
DetectMQTTConnectProtocolStringRegister();
DetectMQTTConnectWillTopicRegister();
DetectMQTTConnectWillMessageRegister();
DetectMQTTConnackSessionPresentRegister();
DetectMQTTPublishTopicRegister();
DetectMQTTPublishMessageRegister();
DetectMQTTSubscribeTopicRegister();
DetectMQTTUnsubscribeTopicRegister();
DetectQuicSniRegister();
DetectQuicUaRegister();
DetectQuicVersionRegister();
@ -742,6 +708,7 @@ void SigTableSetup(void)
ScDetectDHCPRegister();
ScDetectWebsocketRegister();
ScDetectEnipRegister();
ScDetectMqttRegister();
/* close keyword registration */
DetectBufferTypeCloseRegistration();

@ -295,23 +295,6 @@ enum DetectKeywordId {
DETECT_FTPDATA,
DETECT_TARGET,
DETECT_AL_TEMPLATE_BUFFER,
DETECT_AL_MQTT_TYPE,
DETECT_AL_MQTT_FLAGS,
DETECT_AL_MQTT_QOS,
DETECT_AL_MQTT_PROTOCOL_VERSION,
DETECT_AL_MQTT_REASON_CODE,
DETECT_AL_MQTT_CONNECT_FLAGS,
DETECT_AL_MQTT_CONNECT_CLIENTID,
DETECT_AL_MQTT_CONNECT_USERNAME,
DETECT_AL_MQTT_CONNECT_PASSWORD,
DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING,
DETECT_AL_MQTT_CONNECT_WILLTOPIC,
DETECT_AL_MQTT_CONNECT_WILLMESSAGE,
DETECT_AL_MQTT_CONNACK_SESSION_PRESENT,
DETECT_AL_MQTT_PUBLISH_TOPIC,
DETECT_AL_MQTT_PUBLISH_MESSAGE,
DETECT_AL_MQTT_SUBSCRIBE_TOPIC,
DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC,
DETECT_AL_QUIC_VERSION,
DETECT_AL_QUIC_SNI,
DETECT_AL_QUIC_UA,

@ -1,294 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#include "suricata-common.h"
#include "conf.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-engine.h"
#include "detect-engine-content-inspection.h"
#include "detect-mqtt-connack-sessionpresent.h"
#include "util-unittest.h"
#include "rust.h"
#define PARSE_REGEX "^true|false|yes|no$"
static DetectParseRegex parse_regex;
static int mqtt_connack_session_present_id = 0;
static int DetectMQTTConnackSessionPresentMatch(DetectEngineThreadCtx *det_ctx,
Flow *f, uint8_t flags, void *state,
void *txv, const Signature *s,
const SigMatchCtx *ctx);
static int DetectMQTTConnackSessionPresentSetup (DetectEngineCtx *, Signature *, const char *);
void MQTTConnackSessionPresentRegisterTests(void);
void DetectMQTTConnackSessionPresentFree(DetectEngineCtx *de_ctx, void *);
/**
* \brief Registration function for mqtt.connack.session_present: keyword
*/
void DetectMQTTConnackSessionPresentRegister (void)
{
sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].name = "mqtt.connack.session_present";
sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].desc = "match MQTT CONNACK session present flag";
sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].url = "/rules/mqtt-keywords.html#mqtt-connack-session-present";
sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].AppLayerTxMatch = DetectMQTTConnackSessionPresentMatch;
sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].Setup = DetectMQTTConnackSessionPresentSetup;
sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].Free = DetectMQTTConnackSessionPresentFree;
#ifdef UNITTESTS
sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].RegisterTests = MQTTConnackSessionPresentRegisterTests;
#endif
DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
DetectAppLayerInspectEngineRegister("mqtt.connack.session_present", ALPROTO_MQTT,
SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL);
mqtt_connack_session_present_id = DetectBufferTypeGetByName("mqtt.connack.session_present");
}
/**
* \internal
* \brief Function to match session_present flag of an MQTT CONNACK message
*
* \param det_ctx Pointer to the pattern matcher thread.
* \param f Pointer to the current flow.
* \param flags Flags.
* \param state App layer state.
* \param txv Pointer to the transaction.
* \param s Pointer to the Signature.
* \param ctx Pointer to the sigmatch that we will cast into DetectMQTTConnackSessionPresentData.
*
* \retval 0 no match.
* \retval 1 match.
*/
static int DetectMQTTConnackSessionPresentMatch(DetectEngineThreadCtx *det_ctx,
Flow *f, uint8_t flags, void *state,
void *txv, const Signature *s,
const SigMatchCtx *ctx)
{
const bool *de = (const bool *)ctx;
bool value = false;
if (!de)
return 0;
if (rs_mqtt_tx_get_connack_sessionpresent(txv, &value) ==0 ) {
return 0;
}
if (value != *de) {
return 0;
}
return 1;
}
/**
* \internal
* \brief This function is used to parse options passed via mqtt.connack.session_present: keyword
*
* \param rawstr Pointer to the user provided options
*
* \retval de pointer to DetectMQTTConnackSessionPresentData on success
* \retval NULL on failure
*/
static bool *DetectMQTTConnackSessionPresentParse(const char *rawstr)
{
bool *de = NULL;
de = SCMalloc(sizeof(bool));
if (unlikely(de == NULL))
return NULL;
*de = false;
if (strcmp(rawstr, "yes") == 0) {
*de = true;
} else if (strcmp(rawstr, "true") == 0) {
*de = true;
} else if (strcmp(rawstr, "no") == 0) {
*de = false;
} else if (strcmp(rawstr, "false") == 0) {
*de = false;
} else {
SCLogError("invalid session_present flag definition: %s", rawstr);
goto error;
}
return de;
error:
/* de can't be NULL here */
SCFree(de);
return NULL;
}
/**
* \internal
* \brief this function is used to add the parsed type query into the current signature
*
* \param de_ctx pointer to the Detection Engine Context
* \param s pointer to the Current Signature
* \param rawstr pointer to the user provided options
*
* \retval 0 on Success
* \retval -1 on Failure
*/
static int DetectMQTTConnackSessionPresentSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
{
bool *de = NULL;
if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0)
return -1;
de = DetectMQTTConnackSessionPresentParse(rawstr);
if (de == NULL)
goto error;
if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_CONNACK_SESSION_PRESENT, (SigMatchCtx *)de,
mqtt_connack_session_present_id) == NULL) {
goto error;
}
return 0;
error:
if (de != NULL)
SCFree(de);
return -1;
}
/**
* \internal
* \brief this function will free memory associated with DetectMQTTConnackSessionPresentData
*
* \param de pointer to DetectMQTTConnackSessionPresentData
*/
void DetectMQTTConnackSessionPresentFree(DetectEngineCtx *de_ctx, void *de_ptr)
{
if (de_ptr != NULL)
SCFree(de_ptr);
}
/*
* ONLY TESTS BELOW THIS COMMENT
*/
#ifdef UNITTESTS
/**
* \test MQTTConnackSessionPresentTestParse01 is a test for a valid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTConnackSessionPresentTestParse01 (void)
{
bool *de = NULL;
de = DetectMQTTConnackSessionPresentParse("yes");
FAIL_IF_NULL(de);
DetectMQTTConnackSessionPresentFree(NULL, de);
de = DetectMQTTConnackSessionPresentParse("true");
FAIL_IF_NULL(de);
DetectMQTTConnackSessionPresentFree(NULL, de);
de = DetectMQTTConnackSessionPresentParse("false");
FAIL_IF_NULL(de);
DetectMQTTConnackSessionPresentFree(NULL, de);
de = DetectMQTTConnackSessionPresentParse("no");
FAIL_IF_NULL(de);
DetectMQTTConnackSessionPresentFree(NULL, de);
PASS;
}
/**
* \test MQTTConnackSessionPresentTestParse02 is a test for an invalid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTConnackSessionPresentTestParse02 (void)
{
bool *de = NULL;
de = DetectMQTTConnackSessionPresentParse("nix");
if (de) {
DetectMQTTConnackSessionPresentFree(NULL, de);
FAIL;
}
PASS;
}
/**
* \test MQTTConnackSessionPresentTestParse03 is a test for an invalid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTConnackSessionPresentTestParse03 (void)
{
bool *de = NULL;
de = DetectMQTTConnackSessionPresentParse("");
if (de) {
DetectMQTTConnackSessionPresentFree(NULL, de);
FAIL;
}
PASS;
}
/**
* \test MQTTConnackSessionPresentTestParse04 is a test for an invalid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTConnackSessionPresentTestParse04 (void)
{
bool *de = NULL;
de = DetectMQTTConnackSessionPresentParse(",");
if (de) {
DetectMQTTConnackSessionPresentFree(NULL, de);
FAIL;
}
PASS;
}
#endif /* UNITTESTS */
/**
* \brief this function registers unit tests for MQTTConnackSessionPresent
*/
void MQTTConnackSessionPresentRegisterTests(void)
{
#ifdef UNITTESTS
UtRegisterTest("MQTTConnackSessionPresentTestParse01", MQTTConnackSessionPresentTestParse01);
UtRegisterTest("MQTTConnackSessionPresentTestParse02", MQTTConnackSessionPresentTestParse02);
UtRegisterTest("MQTTConnackSessionPresentTestParse03", MQTTConnackSessionPresentTestParse03);
UtRegisterTest("MQTTConnackSessionPresentTestParse04", MQTTConnackSessionPresentTestParse04);
#endif /* UNITTESTS */
}

@ -1,29 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#ifndef SURICATA_DETECT_MQTT_CONNACK_SESSIONPRESENT_H
#define SURICATA_DETECT_MQTT_CONNACK_SESSIONPRESENT_H
void DetectMQTTConnackSessionPresentRegister(void);
#endif /* SURICATA_DETECT_MQTT_CONNACK_SESSIONPRESENT_H */

@ -1,92 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*
* Implements the mqtt.connect.clientid sticky buffer
*/
#include "suricata-common.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-engine.h"
#include "detect-engine-mpm.h"
#include "detect-engine-prefilter.h"
#include "detect-mqtt-connect-clientid.h"
#include "rust.h"
#define KEYWORD_NAME "mqtt.connect.clientid"
#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-clientid"
#define BUFFER_NAME "mqtt.connect.clientid"
#define BUFFER_DESC "MQTT CONNECT client ID"
static int g_buffer_id = 0;
static int DetectMQTTConnectClientIDSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
{
if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0)
return -1;
if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0)
return -1;
return 0;
}
static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
const DetectEngineTransforms *transforms,
Flow *_f, const uint8_t _flow_flags,
void *txv, const int list_id)
{
InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
if (buffer->inspect == NULL) {
const uint8_t *b = NULL;
uint32_t b_len = 0;
if (rs_mqtt_tx_get_connect_clientid(txv, &b, &b_len) != 1)
return NULL;
if (b == NULL || b_len == 0)
return NULL;
InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len);
InspectionBufferApplyTransforms(buffer, transforms);
}
return buffer;
}
void DetectMQTTConnectClientIDRegister(void)
{
/* mqtt.connect.clientid sticky buffer */
sigmatch_table[DETECT_AL_MQTT_CONNECT_CLIENTID].name = KEYWORD_NAME;
sigmatch_table[DETECT_AL_MQTT_CONNECT_CLIENTID].desc = "sticky buffer to match on the MQTT CONNECT client ID";
sigmatch_table[DETECT_AL_MQTT_CONNECT_CLIENTID].url = "/rules/" KEYWORD_DOC;
sigmatch_table[DETECT_AL_MQTT_CONNECT_CLIENTID].Setup = DetectMQTTConnectClientIDSetup;
sigmatch_table[DETECT_AL_MQTT_CONNECT_CLIENTID].flags |= SIGMATCH_NOOPT;
DetectAppLayerInspectEngineRegister(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0,
DetectEngineInspectBufferGeneric, GetData);
DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister,
GetData, ALPROTO_MQTT, 1);
DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC);
g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME);
SCLogDebug("registering " BUFFER_NAME " rule option");
}

@ -1,29 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#ifndef SURICATA_DETECT_MQTT_CONNECT_CLIENTID_H
#define SURICATA_DETECT_MQTT_CONNECT_CLIENTID_H
void DetectMQTTConnectClientIDRegister(void);
#endif /* SURICATA_DETECT_MQTT_CONNECT_CLIENTID_H */

@ -1,385 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#include "suricata-common.h"
#include "conf.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-engine.h"
#include "detect-engine-content-inspection.h"
#include "detect-mqtt-connect-flags.h"
#include "util-unittest.h"
#include "rust.h"
#define PARSE_REGEX "(?: *,?!?(?:username|password|will|will_retain|clean_session))+"
static DetectParseRegex parse_regex;
static int mqtt_connect_flags_id = 0;
static int DetectMQTTConnectFlagsMatch(DetectEngineThreadCtx *det_ctx,
Flow *f, uint8_t flags, void *state,
void *txv, const Signature *s,
const SigMatchCtx *ctx);
static int DetectMQTTConnectFlagsSetup (DetectEngineCtx *, Signature *, const char *);
void MQTTConnectFlagsRegisterTests(void);
void DetectMQTTConnectFlagsFree(DetectEngineCtx *de_ctx, void *);
typedef struct DetectMQTTConnectFlagsData_ {
MQTTFlagState username,
password,
will,
will_retain,
clean_session;
} DetectMQTTConnectFlagsData;
/**
* \brief Registration function for mqtt.connect.flags: keyword
*/
void DetectMQTTConnectFlagsRegister (void)
{
sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].name = "mqtt.connect.flags";
sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].desc = "match MQTT CONNECT variable header flags";
sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].url = "/rules/mqtt-keywords.html#mqtt-connect-flags";
sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].AppLayerTxMatch = DetectMQTTConnectFlagsMatch;
sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].Setup = DetectMQTTConnectFlagsSetup;
sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].Free = DetectMQTTConnectFlagsFree;
#ifdef UNITTESTS
sigmatch_table[DETECT_AL_MQTT_CONNECT_FLAGS].RegisterTests = MQTTConnectFlagsRegisterTests;
#endif
DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
DetectAppLayerInspectEngineRegister("mqtt.connect.flags", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1,
DetectEngineInspectGenericList, NULL);
mqtt_connect_flags_id = DetectBufferTypeGetByName("mqtt.connect.flags");
}
/**
* \internal
* \brief Function to match variable header flags of an MQTT CONNECT Tx
*
* \param det_ctx Pointer to the pattern matcher thread.
* \param f Pointer to the current flow.
* \param flags Flags.
* \param state App layer state.
* \param txv Pointer to the transaction.
* \param s Pointer to the Signature.
* \param ctx Pointer to the sigmatch that we will cast into DetectMQTTConnectFlagsData.
*
* \retval 0 no match.
* \retval 1 match.
*/
static int DetectMQTTConnectFlagsMatch(DetectEngineThreadCtx *det_ctx,
Flow *f, uint8_t flags, void *state,
void *txv, const Signature *s,
const SigMatchCtx *ctx)
{
const DetectMQTTConnectFlagsData *de = (const DetectMQTTConnectFlagsData *)ctx;
if (!de)
return 0;
return rs_mqtt_tx_has_connect_flags(txv, de->username, de->password, de->will,
de->will_retain, de->clean_session);
}
/**
* \internal
* \brief This function is used to parse options passed via mqtt.connect.flags: keyword
*
* \param rawstr Pointer to the user provided options
*
* \retval de pointer to DetectMQTTConnectFlagsData on success
* \retval NULL on failure
*/
static DetectMQTTConnectFlagsData *DetectMQTTConnectFlagsParse(const char *rawstr)
{
char copy[strlen(rawstr) + 1];
DetectMQTTConnectFlagsData *de = SCCalloc(1, sizeof(DetectMQTTConnectFlagsData));
if (unlikely(de == NULL))
return NULL;
pcre2_match_data *match = NULL;
int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0);
if (ret < 1) {
SCLogError("invalid flag definition: %s", rawstr);
goto error;
}
de->username = de->password = de->will = MQTT_DONT_CARE;
de->will_retain = de->clean_session = MQTT_DONT_CARE;
strlcpy(copy, rawstr, sizeof(copy));
char *xsaveptr = NULL;
char *flagv = strtok_r(copy, ",", &xsaveptr);
while (flagv != NULL) {
while (*flagv != '\0' && isblank(*flagv)) {
flagv++;
}
if (strlen(flagv) < 2) {
SCLogError("malformed flag value: %s", flagv);
goto error;
} else {
int offset = 0;
MQTTFlagState fs_to_set = MQTT_MUST_BE_SET;
if (flagv[0] == '!') {
/* negated flag */
offset = 1; /* skip negation operator during comparison */
fs_to_set = MQTT_CANT_BE_SET;
}
if (strcmp(flagv+offset, "username") == 0) {
if (de->username != MQTT_DONT_CARE) {
SCLogError("duplicate flag definition: %s", flagv);
goto error;
}
de->username = fs_to_set;
} else if (strcmp(flagv+offset, "password") == 0) {
if (de->password != MQTT_DONT_CARE) {
SCLogError("duplicate flag definition: %s", flagv);
goto error;
}
de->password = fs_to_set;
} else if (strcmp(flagv+offset, "will") == 0) {
if (de->will != MQTT_DONT_CARE) {
SCLogError("duplicate flag definition: %s", flagv);
goto error;
}
de->will = fs_to_set;
} else if (strcmp(flagv+offset, "will_retain") == 0) {
if (de->will_retain != MQTT_DONT_CARE) {
SCLogError("duplicate flag definition: %s", flagv);
goto error;
}
de->will_retain = fs_to_set;
} else if (strcmp(flagv+offset, "clean_session") == 0) {
if (de->clean_session != MQTT_DONT_CARE) {
SCLogError("duplicate flag definition: %s", flagv);
goto error;
}
de->clean_session = fs_to_set;
} else {
SCLogError("invalid flag definition: %s", flagv);
goto error;
}
}
flagv = strtok_r(NULL, ",", &xsaveptr);
}
pcre2_match_data_free(match);
return de;
error:
if (match) {
pcre2_match_data_free(match);
}
if (de)
SCFree(de);
return NULL;
}
/**
* \internal
* \brief this function is used to add the parsed type query into the current signature
*
* \param de_ctx pointer to the Detection Engine Context
* \param s pointer to the Current Signature
* \param rawstr pointer to the user provided options
*
* \retval 0 on Success
* \retval -1 on Failure
*/
static int DetectMQTTConnectFlagsSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
{
DetectMQTTConnectFlagsData *de = NULL;
if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0)
return -1;
de = DetectMQTTConnectFlagsParse(rawstr);
if (de == NULL)
goto error;
if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_CONNECT_FLAGS, (SigMatchCtx *)de,
mqtt_connect_flags_id) == NULL) {
goto error;
}
return 0;
error:
if (de != NULL)
SCFree(de);
return -1;
}
/**
* \internal
* \brief this function will free memory associated with DetectMQTTConnectFlagsData
*
* \param de pointer to DetectMQTTConnectFlagsData
*/
void DetectMQTTConnectFlagsFree(DetectEngineCtx *de_ctx, void *de_ptr)
{
if (de_ptr != NULL)
SCFree(de_ptr);
}
/*
* ONLY TESTS BELOW THIS COMMENT
*/
#ifdef UNITTESTS
/**
* \test MQTTConnectFlagsTestParse01 is a test for a valid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTConnectFlagsTestParse01 (void)
{
DetectMQTTConnectFlagsData *de = NULL;
de = DetectMQTTConnectFlagsParse("username");
FAIL_IF_NULL(de);
DetectMQTTConnectFlagsFree(NULL, de);
de = DetectMQTTConnectFlagsParse("username,password,will,will_retain,clean_session");
FAIL_IF_NULL(de);
DetectMQTTConnectFlagsFree(NULL, de);
de = DetectMQTTConnectFlagsParse("!username,!password,!will,!will_retain,!clean_session");
FAIL_IF_NULL(de);
DetectMQTTConnectFlagsFree(NULL, de);
de = DetectMQTTConnectFlagsParse(" username,password");
FAIL_IF_NULL(de);
DetectMQTTConnectFlagsFree(NULL, de);
PASS;
}
/**
* \test MQTTConnectFlagsTestParse02 is a test for an invalid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTConnectFlagsTestParse02 (void)
{
DetectMQTTConnectFlagsData *de = NULL;
de = DetectMQTTConnectFlagsParse("foobar");
if (de) {
DetectMQTTConnectFlagsFree(NULL, de);
FAIL;
}
PASS;
}
/**
* \test MQTTConnectFlagsTestParse03 is a test for an invalid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTConnectFlagsTestParse03 (void)
{
DetectMQTTConnectFlagsData *de = NULL;
de = DetectMQTTConnectFlagsParse("will,!");
if (de) {
DetectMQTTConnectFlagsFree(NULL, de);
FAIL;
}
PASS;
}
/**
* \test MQTTConnectFlagsTestParse04 is a test for an invalid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTConnectFlagsTestParse04 (void)
{
DetectMQTTConnectFlagsData *de = NULL;
de = DetectMQTTConnectFlagsParse("");
if (de) {
DetectMQTTConnectFlagsFree(NULL, de);
FAIL;
}
PASS;
}
/**
* \test MQTTConnectFlagsTestParse05 is a test for an invalid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTConnectFlagsTestParse05 (void)
{
DetectMQTTConnectFlagsData *de = NULL;
de = DetectMQTTConnectFlagsParse("username, username");
if (de) {
DetectMQTTConnectFlagsFree(NULL, de);
FAIL;
}
de = DetectMQTTConnectFlagsParse("!username, username");
if (de) {
DetectMQTTConnectFlagsFree(NULL, de);
FAIL;
}
de = DetectMQTTConnectFlagsParse("!username,password,!password");
if (de) {
DetectMQTTConnectFlagsFree(NULL, de);
FAIL;
}
de = DetectMQTTConnectFlagsParse("will, username,password, !will, will");
if (de) {
DetectMQTTConnectFlagsFree(NULL, de);
FAIL;
}
PASS;
}
#endif /* UNITTESTS */
/**
* \brief this function registers unit tests for MQTTConnectFlags
*/
void MQTTConnectFlagsRegisterTests(void)
{
#ifdef UNITTESTS
UtRegisterTest("MQTTConnectFlagsTestParse01", MQTTConnectFlagsTestParse01);
UtRegisterTest("MQTTConnectFlagsTestParse02", MQTTConnectFlagsTestParse02);
UtRegisterTest("MQTTConnectFlagsTestParse03", MQTTConnectFlagsTestParse03);
UtRegisterTest("MQTTConnectFlagsTestParse04", MQTTConnectFlagsTestParse04);
UtRegisterTest("MQTTConnectFlagsTestParse05", MQTTConnectFlagsTestParse05);
#endif /* UNITTESTS */
}

@ -1,29 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#ifndef SURICATA_DETECT_MQTT_CONNECT_FLAGS_H
#define SURICATA_DETECT_MQTT_CONNECT_FLAGS_H
void DetectMQTTConnectFlagsRegister(void);
#endif /* SURICATA_DETECT_MQTT_CONNECT_FLAGS_H */

@ -1,92 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*
* Implements the mqtt.connect.password sticky buffer
*/
#include "suricata-common.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-engine.h"
#include "detect-engine-mpm.h"
#include "detect-engine-prefilter.h"
#include "detect-mqtt-connect-password.h"
#include "rust.h"
#define KEYWORD_NAME "mqtt.connect.password"
#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-password"
#define BUFFER_NAME "mqtt.connect.password"
#define BUFFER_DESC "MQTT CONNECT password"
static int g_buffer_id = 0;
static int DetectMQTTConnectPasswordSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
{
if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0)
return -1;
if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0)
return -1;
return 0;
}
static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
const DetectEngineTransforms *transforms,
Flow *_f, const uint8_t _flow_flags,
void *txv, const int list_id)
{
InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
if (buffer->inspect == NULL) {
const uint8_t *b = NULL;
uint32_t b_len = 0;
if (rs_mqtt_tx_get_connect_password(txv, &b, &b_len) != 1)
return NULL;
if (b == NULL || b_len == 0)
return NULL;
InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len);
InspectionBufferApplyTransforms(buffer, transforms);
}
return buffer;
}
void DetectMQTTConnectPasswordRegister(void)
{
/* mqtt.connect.password sticky buffer */
sigmatch_table[DETECT_AL_MQTT_CONNECT_PASSWORD].name = KEYWORD_NAME;
sigmatch_table[DETECT_AL_MQTT_CONNECT_PASSWORD].desc = "sticky buffer to match on the MQTT CONNECT password";
sigmatch_table[DETECT_AL_MQTT_CONNECT_PASSWORD].url = "/rules/" KEYWORD_DOC;
sigmatch_table[DETECT_AL_MQTT_CONNECT_PASSWORD].Setup = DetectMQTTConnectPasswordSetup;
sigmatch_table[DETECT_AL_MQTT_CONNECT_PASSWORD].flags |= SIGMATCH_NOOPT;
DetectAppLayerInspectEngineRegister(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0,
DetectEngineInspectBufferGeneric, GetData);
DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister,
GetData, ALPROTO_MQTT, 1);
DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC);
g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME);
SCLogDebug("registering " BUFFER_NAME " rule option");
}

@ -1,29 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#ifndef SURICATA_DETECT_MQTT_CONNECT_PASSWORD_H
#define SURICATA_DETECT_MQTT_CONNECT_PASSWORD_H
void DetectMQTTConnectPasswordRegister(void);
#endif /* SURICATA_DETECT_MQTT_CONNECT_PASSWORD_H */

@ -1,94 +0,0 @@
/* Copyright (C) 2023 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*
* Implements the mqtt.connect.protocolstring sticky buffer
*/
#include "suricata-common.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-engine.h"
#include "detect-engine-mpm.h"
#include "detect-engine-prefilter.h"
#include "detect-mqtt-connect-protocol-string.h"
#include "rust.h"
#define KEYWORD_NAME "mqtt.connect.protocol_string"
#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-protocol_string"
#define BUFFER_NAME "mqtt.connect.protocol_string"
#define BUFFER_DESC "MQTT CONNECT protocol string"
static int g_buffer_id = 0;
static int DetectMQTTConnectProtocolStringSetup(
DetectEngineCtx *de_ctx, Signature *s, const char *arg)
{
if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0)
return -1;
if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0)
return -1;
return 0;
}
static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv,
const int list_id)
{
InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
if (buffer->inspect == NULL) {
const uint8_t *b = NULL;
uint32_t b_len = 0;
if (rs_mqtt_tx_get_connect_protocol_string(txv, &b, &b_len) != 1)
return NULL;
if (b == NULL || b_len == 0)
return NULL;
InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len);
InspectionBufferApplyTransforms(buffer, transforms);
}
return buffer;
}
void DetectMQTTConnectProtocolStringRegister(void)
{
/* mqtt.connect.protocol_string sticky buffer */
sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].name = KEYWORD_NAME;
sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].desc =
"sticky buffer to match on the MQTT CONNECT protocol string";
sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].url = "/rules/" KEYWORD_DOC;
sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].Setup =
DetectMQTTConnectProtocolStringSetup;
sigmatch_table[DETECT_AL_MQTT_CONNECT_PROTOCOL_STRING].flags |= SIGMATCH_NOOPT;
DetectAppLayerInspectEngineRegister(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0,
DetectEngineInspectBufferGeneric, GetData);
DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister,
GetData, ALPROTO_MQTT, 1);
DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC);
g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME);
SCLogDebug("registering " BUFFER_NAME " rule option");
}

@ -1,29 +0,0 @@
/* Copyright (C) 2023 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#ifndef SURICATA_DETECT_MQTT_CONNECT_PROTOCOLSTRING_H
#define SURICATA_DETECT_MQTT_CONNECT_PROTOCOLSTRING_H
void DetectMQTTConnectProtocolStringRegister(void);
#endif /* SURICATA_DETECT_MQTT_CONNECT_PROTOCOLSTRING_H */

@ -1,92 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*
* Implements the mqtt.connect.username sticky buffer
*/
#include "suricata-common.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-engine.h"
#include "detect-engine-mpm.h"
#include "detect-engine-prefilter.h"
#include "detect-mqtt-connect-username.h"
#include "rust.h"
#define KEYWORD_NAME "mqtt.connect.username"
#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-username"
#define BUFFER_NAME "mqtt.connect.username"
#define BUFFER_DESC "MQTT CONNECT username"
static int g_buffer_id = 0;
static int DetectMQTTConnectUsernameSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
{
if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0)
return -1;
if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0)
return -1;
return 0;
}
static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
const DetectEngineTransforms *transforms,
Flow *_f, const uint8_t _flow_flags,
void *txv, const int list_id)
{
InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
if (buffer->inspect == NULL) {
const uint8_t *b = NULL;
uint32_t b_len = 0;
if (rs_mqtt_tx_get_connect_username(txv, &b, &b_len) != 1)
return NULL;
if (b == NULL || b_len == 0)
return NULL;
InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len);
InspectionBufferApplyTransforms(buffer, transforms);
}
return buffer;
}
void DetectMQTTConnectUsernameRegister(void)
{
/* mqtt.connect.username sticky buffer */
sigmatch_table[DETECT_AL_MQTT_CONNECT_USERNAME].name = KEYWORD_NAME;
sigmatch_table[DETECT_AL_MQTT_CONNECT_USERNAME].desc = "sticky buffer to match on the MQTT CONNECT username";
sigmatch_table[DETECT_AL_MQTT_CONNECT_USERNAME].url = "/rules/" KEYWORD_DOC;
sigmatch_table[DETECT_AL_MQTT_CONNECT_USERNAME].Setup = DetectMQTTConnectUsernameSetup;
sigmatch_table[DETECT_AL_MQTT_CONNECT_USERNAME].flags |= SIGMATCH_NOOPT;
DetectAppLayerInspectEngineRegister(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0,
DetectEngineInspectBufferGeneric, GetData);
DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister,
GetData, ALPROTO_MQTT, 1);
DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC);
g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME);
SCLogDebug("registering " BUFFER_NAME " rule option");
}

@ -1,29 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#ifndef SURICATA_DETECT_MQTT_CONNECT_USERNAME_H
#define SURICATA_DETECT_MQTT_CONNECT_USERNAME_H
void DetectMQTTConnectUsernameRegister(void);
#endif /* SURICATA_DETECT_MQTT_CONNECT_USERNAME_H */

@ -1,92 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*
* Implements the mqtt.connect.willmessage sticky buffer
*/
#include "suricata-common.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-engine.h"
#include "detect-engine-mpm.h"
#include "detect-engine-prefilter.h"
#include "detect-mqtt-connect-willmessage.h"
#include "rust.h"
#define KEYWORD_NAME "mqtt.connect.willmessage"
#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-willmessage"
#define BUFFER_NAME "mqtt.connect.willmessage"
#define BUFFER_DESC "MQTT CONNECT will message"
static int g_buffer_id = 0;
static int DetectMQTTConnectWillMessageSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
{
if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0)
return -1;
if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0)
return -1;
return 0;
}
static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
const DetectEngineTransforms *transforms,
Flow *_f, const uint8_t _flow_flags,
void *txv, const int list_id)
{
InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
if (buffer->inspect == NULL) {
const uint8_t *b = NULL;
uint32_t b_len = 0;
if (rs_mqtt_tx_get_connect_willmessage(txv, &b, &b_len) != 1)
return NULL;
if (b == NULL || b_len == 0)
return NULL;
InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len);
InspectionBufferApplyTransforms(buffer, transforms);
}
return buffer;
}
void DetectMQTTConnectWillMessageRegister(void)
{
/* mqtt.connect.willmessage sticky buffer */
sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLMESSAGE].name = KEYWORD_NAME;
sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLMESSAGE].desc = "sticky buffer to match on the MQTT CONNECT will message";
sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLMESSAGE].url = "/rules/" KEYWORD_DOC;
sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLMESSAGE].Setup = DetectMQTTConnectWillMessageSetup;
sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLMESSAGE].flags |= SIGMATCH_NOOPT;
DetectAppLayerInspectEngineRegister(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0,
DetectEngineInspectBufferGeneric, GetData);
DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister,
GetData, ALPROTO_MQTT, 1);
DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC);
g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME);
SCLogDebug("registering " BUFFER_NAME " rule option");
}

@ -1,29 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#ifndef SURICATA_DETECT_MQTT_CONNECT_WILLMESSAGE_H
#define SURICATA_DETECT_MQTT_CONNECT_WILLMESSAGE_H
void DetectMQTTConnectWillMessageRegister(void);
#endif /* SURICATA_DETECT_MQTT_CONNECT_WILLMESSAGE_H */

@ -1,92 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*
* Implements the mqtt.connect.willtopic sticky buffer
*/
#include "suricata-common.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-engine.h"
#include "detect-engine-mpm.h"
#include "detect-engine-prefilter.h"
#include "detect-mqtt-connect-willtopic.h"
#include "rust.h"
#define KEYWORD_NAME "mqtt.connect.willtopic"
#define KEYWORD_DOC "mqtt-keywords.html#mqtt-connect-willtopic"
#define BUFFER_NAME "mqtt.connect.willtopic"
#define BUFFER_DESC "MQTT CONNECT will topic"
static int g_buffer_id = 0;
static int DetectMQTTConnectWillTopicSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
{
if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0)
return -1;
if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0)
return -1;
return 0;
}
static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
const DetectEngineTransforms *transforms,
Flow *_f, const uint8_t _flow_flags,
void *txv, const int list_id)
{
InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
if (buffer->inspect == NULL) {
const uint8_t *b = NULL;
uint32_t b_len = 0;
if (rs_mqtt_tx_get_connect_willtopic(txv, &b, &b_len) != 1)
return NULL;
if (b == NULL || b_len == 0)
return NULL;
InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len);
InspectionBufferApplyTransforms(buffer, transforms);
}
return buffer;
}
void DetectMQTTConnectWillTopicRegister(void)
{
/* mqtt.connect.willtopic sticky buffer */
sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLTOPIC].name = KEYWORD_NAME;
sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLTOPIC].desc = "sticky buffer to match on the MQTT CONNECT will topic";
sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLTOPIC].url = "/rules/" KEYWORD_DOC;
sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLTOPIC].Setup = DetectMQTTConnectWillTopicSetup;
sigmatch_table[DETECT_AL_MQTT_CONNECT_WILLTOPIC].flags |= SIGMATCH_NOOPT;
DetectAppLayerInspectEngineRegister(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0,
DetectEngineInspectBufferGeneric, GetData);
DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister,
GetData, ALPROTO_MQTT, 1);
DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC);
g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME);
SCLogDebug("registering " BUFFER_NAME " rule option");
}

@ -1,29 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#ifndef SURICATA_DETECT_MQTT_CONNECT_WILLTOPIC_H
#define SURICATA_DETECT_MQTT_CONNECT_WILLTOPIC_H
void DetectMQTTConnectWillTopicRegister(void);
#endif /* SURICATA_DETECT_MQTT_CONNECT_WILLTOPIC_H */

@ -1,359 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#include "suricata-common.h"
#include "conf.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-engine.h"
#include "detect-engine-content-inspection.h"
#include "detect-mqtt-flags.h"
#include "util-unittest.h"
#include "rust.h"
#define PARSE_REGEX "(?: *,?!?(?:retain|dup))+"
static DetectParseRegex parse_regex;
static int mqtt_flags_id = 0;
static int DetectMQTTFlagsMatch(DetectEngineThreadCtx *det_ctx,
Flow *f, uint8_t flags, void *state,
void *txv, const Signature *s,
const SigMatchCtx *ctx);
static int DetectMQTTFlagsSetup (DetectEngineCtx *, Signature *, const char *);
void MQTTFlagsRegisterTests(void);
void DetectMQTTFlagsFree(DetectEngineCtx *de_ctx, void *);
typedef struct DetectMQTTFlagsData_ {
MQTTFlagState retain, dup;
} DetectMQTTFlagsData;
/**
* \brief Registration function for mqtt.flags: keyword
*/
void DetectMQTTFlagsRegister (void)
{
sigmatch_table[DETECT_AL_MQTT_FLAGS].name = "mqtt.flags";
sigmatch_table[DETECT_AL_MQTT_FLAGS].desc = "match MQTT fixed header flags";
sigmatch_table[DETECT_AL_MQTT_FLAGS].url = "/rules/mqtt-keywords.html#mqtt-flags";
sigmatch_table[DETECT_AL_MQTT_FLAGS].AppLayerTxMatch = DetectMQTTFlagsMatch;
sigmatch_table[DETECT_AL_MQTT_FLAGS].Setup = DetectMQTTFlagsSetup;
sigmatch_table[DETECT_AL_MQTT_FLAGS].Free = DetectMQTTFlagsFree;
#ifdef UNITTESTS
sigmatch_table[DETECT_AL_MQTT_FLAGS].RegisterTests = MQTTFlagsRegisterTests;
#endif
DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
DetectAppLayerInspectEngineRegister(
"mqtt.flags", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL);
mqtt_flags_id = DetectBufferTypeGetByName("mqtt.flags");
}
/**
* \internal
* \brief Function to match fixed header flags of an MQTT Tx
*
* \param det_ctx Pointer to the pattern matcher thread.
* \param f Pointer to the current flow.
* \param flags Flags.
* \param state App layer state.
* \param txv Pointer to the transaction.
* \param s Pointer to the Signature.
* \param ctx Pointer to the sigmatch that we will cast into DetectMQTTFlagsData.
*
* \retval 0 no match.
* \retval 1 match.
*/
static int DetectMQTTFlagsMatch(DetectEngineThreadCtx *det_ctx,
Flow *f, uint8_t flags, void *state,
void *txv, const Signature *s,
const SigMatchCtx *ctx)
{
const DetectMQTTFlagsData *de = (const DetectMQTTFlagsData *)ctx;
if (!de)
return 0;
return rs_mqtt_tx_has_flags(txv, de->retain, de->dup);
}
/**
* \internal
* \brief This function is used to parse options passed via mqtt.flags: keyword
*
* \param rawstr Pointer to the user provided options
*
* \retval de pointer to DetectMQTTFlagsData on success
* \retval NULL on failure
*/
static DetectMQTTFlagsData *DetectMQTTFlagsParse(const char *rawstr)
{
DetectMQTTFlagsData *de = SCCalloc(1, sizeof(DetectMQTTFlagsData));
if (unlikely(de == NULL))
return NULL;
pcre2_match_data *match = NULL;
int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0);
if (ret < 1) {
SCLogError("invalid flag definition: %s", rawstr);
if (match) {
pcre2_match_data_free(match);
}
SCFree(de);
return NULL;
}
de->retain = de->dup = MQTT_DONT_CARE;
char copy[strlen(rawstr)+1];
strlcpy(copy, rawstr, sizeof(copy));
char *xsaveptr = NULL;
/* Iterate through comma-separated string... */
char *flagv = strtok_r(copy, ",", &xsaveptr);
while (flagv != NULL) {
/* skip blanks */
while (*flagv != '\0' && isblank(*flagv)) {
flagv++;
}
if (strlen(flagv) < 2) {
/* flags have a minimum length */
SCLogError("malformed flag value: %s", flagv);
goto error;
} else {
int offset = 0;
MQTTFlagState fs_to_set = MQTT_MUST_BE_SET;
if (flagv[0] == '!') {
/* negated flag */
offset = 1; /* skip negation operator during comparison */
fs_to_set = MQTT_CANT_BE_SET;
}
if (strcmp(flagv+offset, "dup") == 0) {
if (de->dup != MQTT_DONT_CARE) {
SCLogError("duplicate flag definition: %s", flagv);
goto error;
}
de->dup = fs_to_set;
} else if (strcmp(flagv+offset, "retain") == 0) {
if (de->retain != MQTT_DONT_CARE) {
SCLogError("duplicate flag definition: %s", flagv);
goto error;
}
de->retain = fs_to_set;
} else {
SCLogError("invalid flag definition: %s", flagv);
goto error;
}
}
flagv = strtok_r(NULL, ",", &xsaveptr);
}
pcre2_match_data_free(match);
return de;
error:
if (match) {
pcre2_match_data_free(match);
}
if (de)
SCFree(de);
return NULL;
}
/**
* \internal
* \brief this function is used to add the parsed type query into the current signature
*
* \param de_ctx pointer to the Detection Engine Context
* \param s pointer to the Current Signature
* \param rawstr pointer to the user provided options
*
* \retval 0 on Success
* \retval -1 on Failure
*/
static int DetectMQTTFlagsSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
{
DetectMQTTFlagsData *de = NULL;
if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0)
return -1;
de = DetectMQTTFlagsParse(rawstr);
if (de == NULL)
goto error;
if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_FLAGS, (SigMatchCtx *)de, mqtt_flags_id) ==
NULL) {
goto error;
}
return 0;
error:
if (de != NULL)
SCFree(de);
return -1;
}
/**
* \internal
* \brief this function will free memory associated with DetectMQTTFlagsData
*
* \param de pointer to DetectMQTTFlagsData
*/
void DetectMQTTFlagsFree(DetectEngineCtx *de_ctx, void *de_ptr)
{
if (de_ptr != NULL)
SCFree(de_ptr);
}
/*
* ONLY TESTS BELOW THIS COMMENT
*/
#ifdef UNITTESTS
/**
* \test MQTTFlagsTestParse01 is a test for a valid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTFlagsTestParse01 (void)
{
DetectMQTTFlagsData *de = NULL;
de = DetectMQTTFlagsParse("retain");
FAIL_IF_NULL(de);
DetectMQTTFlagsFree(NULL, de);
de = DetectMQTTFlagsParse("dup");
FAIL_IF_NULL(de);
DetectMQTTFlagsFree(NULL, de);
de = DetectMQTTFlagsParse("retain,dup");
FAIL_IF_NULL(de);
DetectMQTTFlagsFree(NULL, de);
de = DetectMQTTFlagsParse("dup, retain");
FAIL_IF_NULL(de);
DetectMQTTFlagsFree(NULL, de);
PASS;
}
/**
* \test MQTTFlagsTestParse02 is a test for a valid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTFlagsTestParse02 (void)
{
DetectMQTTFlagsData *de = NULL;
de = DetectMQTTFlagsParse("retain,!dup");
FAIL_IF_NULL(de);
DetectMQTTFlagsFree(NULL, de);
PASS;
}
/**
* \test MQTTFlagsTestParse03 is a test for an invalid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTFlagsTestParse03 (void)
{
DetectMQTTFlagsData *de = NULL;
de = DetectMQTTFlagsParse("ref");
if (de) {
DetectMQTTFlagsFree(NULL, de);
FAIL;
}
PASS;
}
/**
* \test MQTTFlagsTestParse04 is a test for an invalid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTFlagsTestParse04 (void)
{
DetectMQTTFlagsData *de = NULL;
de = DetectMQTTFlagsParse("dup,!");
if (de) {
DetectMQTTFlagsFree(NULL, de);
FAIL;
}
PASS;
}
/**
* \test MQTTFlagsTestParse05 is a test for an invalid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTFlagsTestParse05 (void)
{
DetectMQTTFlagsData *de = NULL;
de = DetectMQTTFlagsParse("dup,!dup");
if (de) {
DetectMQTTFlagsFree(NULL, de);
FAIL;
}
de = DetectMQTTFlagsParse("!retain,retain");
if (de) {
DetectMQTTFlagsFree(NULL, de);
FAIL;
}
PASS;
}
#endif /* UNITTESTS */
/**
* \brief this function registers unit tests for MQTTFlags
*/
void MQTTFlagsRegisterTests(void)
{
#ifdef UNITTESTS
UtRegisterTest("MQTTFlagsTestParse01", MQTTFlagsTestParse01);
UtRegisterTest("MQTTFlagsTestParse02", MQTTFlagsTestParse02);
UtRegisterTest("MQTTFlagsTestParse03", MQTTFlagsTestParse03);
UtRegisterTest("MQTTFlagsTestParse04", MQTTFlagsTestParse04);
UtRegisterTest("MQTTFlagsTestParse05", MQTTFlagsTestParse05);
#endif /* UNITTESTS */
}

@ -1,29 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#ifndef SURICATA_DETECT_MQTT_FLAGS_H
#define SURICATA_DETECT_MQTT_FLAGS_H
void DetectMQTTFlagsRegister(void);
#endif /* SURICATA_DETECT_MQTT_FLAGS_H */

@ -1,248 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#include "suricata-common.h"
#include "conf.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-engine.h"
#include "detect-engine-content-inspection.h"
#include "detect-engine-uint.h"
#include "detect-mqtt-protocol-version.h"
#include "util-byte.h"
#include "util-unittest.h"
#include "rust.h"
static int mqtt_protocol_version_id = 0;
static int DetectMQTTProtocolVersionMatch(DetectEngineThreadCtx *det_ctx,
Flow *f, uint8_t flags, void *state,
void *txv, const Signature *s,
const SigMatchCtx *ctx);
static int DetectMQTTProtocolVersionSetup (DetectEngineCtx *, Signature *, const char *);
void MQTTProtocolVersionRegisterTests(void);
void DetectMQTTProtocolVersionFree(DetectEngineCtx *de_ctx, void *);
/**
* \brief Registration function for mqtt.protocol_version: keyword
*/
void DetectMQTTProtocolVersionRegister (void)
{
sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].name = "mqtt.protocol_version";
sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].desc = "match MQTT protocol version";
sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].url = "/rules/mqtt-keywords.html#mqtt-protocol-version";
sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].AppLayerTxMatch = DetectMQTTProtocolVersionMatch;
sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].Setup = DetectMQTTProtocolVersionSetup;
sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].Free = DetectMQTTProtocolVersionFree;
#ifdef UNITTESTS
sigmatch_table[DETECT_AL_MQTT_PROTOCOL_VERSION].RegisterTests = MQTTProtocolVersionRegisterTests;
#endif
DetectAppLayerInspectEngineRegister("mqtt.protocol_version", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1,
DetectEngineInspectGenericList, NULL);
mqtt_protocol_version_id = DetectBufferTypeGetByName("mqtt.protocol_version");
}
/**
* \internal
* \brief Function to match protocol version of an MQTT Tx
*
* \param det_ctx Pointer to the pattern matcher thread.
* \param f Pointer to the current flow.
* \param flags Flags.
* \param state App layer state.
* \param txv Pointer to the transaction.
* \param s Pointer to the Signature.
* \param ctx Pointer to the sigmatch that we will cast into DetectMQTTProtocolVersionData.
*
* \retval 0 no match.
* \retval 1 match.
*/
static int DetectMQTTProtocolVersionMatch(DetectEngineThreadCtx *det_ctx,
Flow *f, uint8_t flags, void *state,
void *txv, const Signature *s,
const SigMatchCtx *ctx)
{
const DetectU8Data *de = (const DetectU8Data *)ctx;
uint8_t version;
version = rs_mqtt_tx_get_protocol_version(state);
return DetectU8Match(version, de);
}
/**
* \internal
* \brief this function is used to add the parsed sigmatch into the current signature
*
* \param de_ctx pointer to the Detection Engine Context
* \param s pointer to the Current Signature
* \param rawstr pointer to the user provided options
*
* \retval 0 on Success
* \retval -1 on Failure
*/
static int DetectMQTTProtocolVersionSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
{
DetectU8Data *de = NULL;
if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0)
return -1;
de = DetectU8Parse(rawstr);
if (de == NULL)
return -1;
if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_PROTOCOL_VERSION, (SigMatchCtx *)de,
mqtt_protocol_version_id) == NULL) {
goto error;
}
return 0;
error:
if (de != NULL)
rs_detect_u8_free(de);
return -1;
}
/**
* \internal
* \brief this function will free memory associated with DetectMQTTProtocolVersionData
*
* \param de pointer to DetectMQTTProtocolVersionData
*/
void DetectMQTTProtocolVersionFree(DetectEngineCtx *de_ctx, void *de_ptr)
{
rs_detect_u8_free(de_ptr);
}
/*
* ONLY TESTS BELOW THIS COMMENT
*/
#ifdef UNITTESTS
/**
* \test MQTTProtocolVersionTestParse01 is a test for a valid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTProtocolVersionTestParse01 (void)
{
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
FAIL_IF_NULL(de_ctx);
Signature *sig = DetectEngineAppendSig(de_ctx,
"alert ip any any -> any any (mqtt.protocol_version:3; sid:1; rev:1;)");
FAIL_IF_NULL(sig);
sig = DetectEngineAppendSig(de_ctx,
"alert ip any any -> any any (mqtt.protocol_version:3; sid:2; rev:1;)");
FAIL_IF_NULL(sig);
DetectEngineCtxFree(de_ctx);
PASS;
}
/**
* \test MQTTProtocolVersionTestParse02 is a test for a valid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTProtocolVersionTestParse02 (void)
{
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
FAIL_IF_NULL(de_ctx);
Signature *sig = DetectEngineAppendSig(de_ctx,
"alert ip any any -> any any (mqtt.protocol_version:>3; sid:1; rev:1;)");
FAIL_IF_NULL(sig);
sig = DetectEngineAppendSig(de_ctx,
"alert ip any any -> any any (mqtt.protocol_version:<44; sid:2; rev:1;)");
FAIL_IF_NULL(sig);
DetectEngineCtxFree(de_ctx);
PASS;
}
/**
* \test MQTTProtocolVersionTestParse03 is a test for an invalid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTProtocolVersionTestParse03 (void)
{
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
FAIL_IF_NULL(de_ctx);
Signature *sig = DetectEngineAppendSig(de_ctx,
"alert ip any any -> any any (mqtt.protocol_version:; sid:1; rev:1;)");
FAIL_IF_NOT_NULL(sig);
DetectEngineCtxFree(de_ctx);
PASS;
}
/**
* \test MQTTProtocolVersionTestParse04 is a test for an invalid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTProtocolVersionTestParse04 (void)
{
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
FAIL_IF_NULL(de_ctx);
Signature *sig = DetectEngineAppendSig(de_ctx,
"alert ip any any -> any any (mqtt.protocol_version:<444; sid:1; rev:1;)");
FAIL_IF_NOT_NULL(sig);
DetectEngineCtxFree(de_ctx);
PASS;
}
#endif /* UNITTESTS */
/**
* \brief this function registers unit tests for MQTTProtocolVersion
*/
void MQTTProtocolVersionRegisterTests(void)
{
#ifdef UNITTESTS
UtRegisterTest("MQTTProtocolVersionTestParse01", MQTTProtocolVersionTestParse01);
UtRegisterTest("MQTTProtocolVersionTestParse02", MQTTProtocolVersionTestParse02);
UtRegisterTest("MQTTProtocolVersionTestParse03", MQTTProtocolVersionTestParse03);
UtRegisterTest("MQTTProtocolVersionTestParse04", MQTTProtocolVersionTestParse04);
#endif /* UNITTESTS */
}

@ -1,29 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#ifndef SURICATA_DETECT_MQTT_PROTOCOL_VERSION_H
#define SURICATA_DETECT_MQTT_PROTOCOL_VERSION_H
void DetectMQTTProtocolVersionRegister(void);
#endif /* SURICATA_DETECT_MQTT_PROTOCOL_VERSION_H */

@ -1,92 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*
* Implements the mqtt.publish.message sticky buffer
*/
#include "suricata-common.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-engine.h"
#include "detect-engine-mpm.h"
#include "detect-engine-prefilter.h"
#include "detect-mqtt-publish-message.h"
#include "rust.h"
#define KEYWORD_NAME "mqtt.publish.message"
#define KEYWORD_DOC "mqtt-keywords.html#mqtt-publish-message"
#define BUFFER_NAME "mqtt.publish.message"
#define BUFFER_DESC "MQTT PUBLISH message"
static int g_buffer_id = 0;
static int DetectMQTTPublishMessageSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
{
if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0)
return -1;
if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0)
return -1;
return 0;
}
static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
const DetectEngineTransforms *transforms,
Flow *_f, const uint8_t _flow_flags,
void *txv, const int list_id)
{
InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
if (buffer->inspect == NULL) {
const uint8_t *b = NULL;
uint32_t b_len = 0;
if (rs_mqtt_tx_get_publish_message(txv, &b, &b_len) != 1)
return NULL;
if (b == NULL || b_len == 0)
return NULL;
InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len);
InspectionBufferApplyTransforms(buffer, transforms);
}
return buffer;
}
void DetectMQTTPublishMessageRegister(void)
{
/* mqtt.publish.message sticky buffer */
sigmatch_table[DETECT_AL_MQTT_PUBLISH_MESSAGE].name = KEYWORD_NAME;
sigmatch_table[DETECT_AL_MQTT_PUBLISH_MESSAGE].desc = "sticky buffer to match on the MQTT PUBLISH message";
sigmatch_table[DETECT_AL_MQTT_PUBLISH_MESSAGE].url = "/rules/" KEYWORD_DOC;
sigmatch_table[DETECT_AL_MQTT_PUBLISH_MESSAGE].Setup = DetectMQTTPublishMessageSetup;
sigmatch_table[DETECT_AL_MQTT_PUBLISH_MESSAGE].flags |= SIGMATCH_NOOPT;
DetectAppLayerInspectEngineRegister(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0,
DetectEngineInspectBufferGeneric, GetData);
DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister,
GetData, ALPROTO_MQTT, 1);
DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC);
g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME);
SCLogDebug("registering " BUFFER_NAME " rule option");
}

@ -1,29 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#ifndef SURICATA_DETECT_MQTT_PUBLISH_MESSAGE_H
#define SURICATA_DETECT_MQTT_PUBLISH_MESSAGE_H
void DetectMQTTPublishMessageRegister(void);
#endif /* SURICATA_DETECT_MQTT_PUBLISH_MESSAGE_H */

@ -1,92 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*
* Implements the mqtt.publish.topic sticky buffer
*/
#include "suricata-common.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-engine.h"
#include "detect-engine-mpm.h"
#include "detect-engine-prefilter.h"
#include "detect-mqtt-publish-topic.h"
#include "rust.h"
#define KEYWORD_NAME "mqtt.publish.topic"
#define KEYWORD_DOC "mqtt-keywords.html#mqtt-publish-topic"
#define BUFFER_NAME "mqtt.publish.topic"
#define BUFFER_DESC "MQTT PUBLISH topic"
static int g_buffer_id = 0;
static int DetectMQTTPublishTopicSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
{
if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0)
return -1;
if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0)
return -1;
return 0;
}
static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
const DetectEngineTransforms *transforms,
Flow *_f, const uint8_t _flow_flags,
void *txv, const int list_id)
{
InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
if (buffer->inspect == NULL) {
const uint8_t *b = NULL;
uint32_t b_len = 0;
if (rs_mqtt_tx_get_publish_topic(txv, &b, &b_len) != 1)
return NULL;
if (b == NULL || b_len == 0)
return NULL;
InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len);
InspectionBufferApplyTransforms(buffer, transforms);
}
return buffer;
}
void DetectMQTTPublishTopicRegister(void)
{
/* mqtt.publish.topic sticky buffer */
sigmatch_table[DETECT_AL_MQTT_PUBLISH_TOPIC].name = KEYWORD_NAME;
sigmatch_table[DETECT_AL_MQTT_PUBLISH_TOPIC].desc = "sticky buffer to match on the MQTT PUBLISH topic";
sigmatch_table[DETECT_AL_MQTT_PUBLISH_TOPIC].url = "/rules/" KEYWORD_DOC;
sigmatch_table[DETECT_AL_MQTT_PUBLISH_TOPIC].Setup = DetectMQTTPublishTopicSetup;
sigmatch_table[DETECT_AL_MQTT_PUBLISH_TOPIC].flags |= SIGMATCH_NOOPT;
DetectAppLayerInspectEngineRegister(BUFFER_NAME, ALPROTO_MQTT, SIG_FLAG_TOSERVER, 0,
DetectEngineInspectBufferGeneric, GetData);
DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister,
GetData, ALPROTO_MQTT, 1);
DetectBufferTypeSetDescriptionByName(BUFFER_NAME, BUFFER_DESC);
g_buffer_id = DetectBufferTypeGetByName(BUFFER_NAME);
SCLogDebug("registering " BUFFER_NAME " rule option");
}

@ -1,29 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#ifndef SURICATA_DETECT_MQTT_PUBLISH_TOPIC_H
#define SURICATA_DETECT_MQTT_PUBLISH_TOPIC_H
void DetectMQTTPublishTopicRegister(void);
#endif /* SURICATA_DETECT_MQTT_PUBLISH_TOPIC_H */

@ -1,258 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#include "suricata-common.h"
#include "conf.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-engine.h"
#include "detect-engine-content-inspection.h"
#include "detect-mqtt-qos.h"
#include "util-byte.h"
#include "util-unittest.h"
#include "rust.h"
static int mqtt_qos_id = 0;
static int DetectMQTTQosMatch(DetectEngineThreadCtx *det_ctx,
Flow *f, uint8_t flags, void *state,
void *txv, const Signature *s,
const SigMatchCtx *ctx);
static int DetectMQTTQosSetup (DetectEngineCtx *, Signature *, const char *);
void MQTTQosRegisterTests(void);
void DetectMQTTQosFree(DetectEngineCtx *de_ctx, void *);
/**
* \brief Registration function for mqtt.qos: keyword
*/
void DetectMQTTQosRegister (void)
{
sigmatch_table[DETECT_AL_MQTT_QOS].name = "mqtt.qos";
sigmatch_table[DETECT_AL_MQTT_QOS].desc = "match MQTT fixed header QOS level";
sigmatch_table[DETECT_AL_MQTT_QOS].url = "/rules/mqtt-keywords.html#mqtt-qos";
sigmatch_table[DETECT_AL_MQTT_QOS].AppLayerTxMatch = DetectMQTTQosMatch;
sigmatch_table[DETECT_AL_MQTT_QOS].Setup = DetectMQTTQosSetup;
sigmatch_table[DETECT_AL_MQTT_QOS].Free = DetectMQTTQosFree;
#ifdef UNITTESTS
sigmatch_table[DETECT_AL_MQTT_QOS].RegisterTests = MQTTQosRegisterTests;
#endif
DetectAppLayerInspectEngineRegister(
"mqtt.qos", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL);
mqtt_qos_id = DetectBufferTypeGetByName("mqtt.qos");
}
/**
* \internal
* \brief Function to match fixed header QOS field of an MQTT Tx
*
* \param det_ctx Pointer to the pattern matcher thread.
* \param f Pointer to the current flow.
* \param flags Flags.
* \param state App layer state.
* \param txv Pointer to the transaction.
* \param s Pointer to the Signature.
* \param ctx Pointer to the sigmatch that we will cast into uint8_t.
*
* \retval 0 no match.
* \retval 1 match.
*/
static int DetectMQTTQosMatch(DetectEngineThreadCtx *det_ctx,
Flow *f, uint8_t flags, void *state,
void *txv, const Signature *s,
const SigMatchCtx *ctx)
{
const uint8_t *de = (const uint8_t *)ctx;
if (!de)
return 0;
return rs_mqtt_tx_has_qos(txv, *de);
}
/**
* \internal
* \brief This function is used to parse options passed via mqtt.qos: keyword
*
* \param rawstr Pointer to the user provided options
*
* \retval de pointer to DetectMQTTQosData on success
* \retval NULL on failure
*/
static uint8_t *DetectMQTTQosParse(const char *rawstr)
{
uint8_t *de = NULL;
int ret = 0;
uint8_t val;
ret = StringParseU8RangeCheck(&val, 10, 0, rawstr, 0, 2);
if (ret < 0) {
SCLogError("invalid MQTT QOS level: %s", rawstr);
return NULL;
}
de = SCMalloc(sizeof(uint8_t));
if (unlikely(de == NULL))
return NULL;
*de = val;
return de;
}
/**
* \internal
* \brief this function is used to add the parsed sigmatch into the current signature
*
* \param de_ctx pointer to the Detection Engine Context
* \param s pointer to the Current Signature
* \param rawstr pointer to the user provided options
*
* \retval 0 on Success
* \retval -1 on Failure
*/
static int DetectMQTTQosSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
{
uint8_t *de = NULL;
if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0)
return -1;
de = DetectMQTTQosParse(rawstr);
if (de == NULL)
goto error;
if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_QOS, (SigMatchCtx *)de, mqtt_qos_id) ==
NULL) {
goto error;
}
return 0;
error:
if (de != NULL)
SCFree(de);
return -1;
}
/**
* \internal
* \brief this function will free memory associated with DetectMQTTQosData
*
* \param de pointer to DetectMQTTQosData
*/
void DetectMQTTQosFree(DetectEngineCtx *de_ctx, void *de_ptr)
{
if (de_ptr != NULL)
SCFree(de_ptr);
}
/*
* ONLY TESTS BELOW THIS COMMENT
*/
#ifdef UNITTESTS
/**
* \test MQTTQosTestParse01 is a test for a valid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTQosTestParse01 (void)
{
uint8_t *de = NULL;
de = DetectMQTTQosParse("0");
FAIL_IF_NULL(de);
FAIL_IF_NOT(*de == 0);
DetectMQTTQosFree(NULL, de);
de = DetectMQTTQosParse(" 0");
FAIL_IF_NULL(de);
FAIL_IF_NOT(*de == 0);
DetectMQTTQosFree(NULL, de);
de = DetectMQTTQosParse("1");
FAIL_IF_NULL(de);
FAIL_IF_NOT(*de == 1);
DetectMQTTQosFree(NULL, de);
de = DetectMQTTQosParse("2");
FAIL_IF_NULL(de);
FAIL_IF_NOT(*de == 2);
DetectMQTTQosFree(NULL, de);
PASS;
}
/**
* \test MQTTQosTestParse02 is a test for an invalid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTQosTestParse02 (void)
{
uint8_t *de = NULL;
de = DetectMQTTQosParse("3");
if (de) {
DetectMQTTQosFree(NULL, de);
FAIL;
}
PASS;
}
/**
* \test MQTTQosTestParse04 is a test for an invalid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTQosTestParse03 (void)
{
uint8_t *de = NULL;
de = DetectMQTTQosParse("12");
if (de) {
DetectMQTTQosFree(NULL, de);
FAIL;
}
PASS;
}
#endif /* UNITTESTS */
/**
* \brief this function registers unit tests for MQTTQos
*/
void MQTTQosRegisterTests(void)
{
#ifdef UNITTESTS
UtRegisterTest("MQTTQosTestParse01", MQTTQosTestParse01);
UtRegisterTest("MQTTQosTestParse02", MQTTQosTestParse02);
UtRegisterTest("MQTTQosTestParse03", MQTTQosTestParse03);
#endif /* UNITTESTS */
}

@ -1,29 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#ifndef SURICATA_DETECT_MQTT_QOS_H
#define SURICATA_DETECT_MQTT_QOS_H
void DetectMQTTQosRegister(void);
#endif /* SURICATA_DETECT_MQTT_QOS_H */

@ -1,294 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#include "suricata-common.h"
#include "conf.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-engine.h"
#include "detect-engine-content-inspection.h"
#include "detect-mqtt-reason-code.h"
#include "util-byte.h"
#include "util-unittest.h"
#include "rust.h"
#define PARSE_REGEX "^\\s*\\d+\\s*$"
static DetectParseRegex parse_regex;
static int mqtt_reason_code_id = 0;
static int DetectMQTTReasonCodeMatch(DetectEngineThreadCtx *det_ctx,
Flow *f, uint8_t flags, void *state,
void *txv, const Signature *s,
const SigMatchCtx *ctx);
static int DetectMQTTReasonCodeSetup (DetectEngineCtx *, Signature *, const char *);
void MQTTReasonCodeRegisterTests(void);
void DetectMQTTReasonCodeFree(DetectEngineCtx *de_ctx, void *);
/**
* \brief Registration function for mqtt.reason_code: keyword
*/
void DetectMQTTReasonCodeRegister (void)
{
sigmatch_table[DETECT_AL_MQTT_REASON_CODE].name = "mqtt.reason_code";
sigmatch_table[DETECT_AL_MQTT_REASON_CODE].alias = "mqtt.connack.return_code";
sigmatch_table[DETECT_AL_MQTT_REASON_CODE].desc = "match MQTT 5.0+ reason code";
sigmatch_table[DETECT_AL_MQTT_REASON_CODE].url = "/rules/mqtt-keywords.html#mqtt-reason-code";
sigmatch_table[DETECT_AL_MQTT_REASON_CODE].AppLayerTxMatch = DetectMQTTReasonCodeMatch;
sigmatch_table[DETECT_AL_MQTT_REASON_CODE].Setup = DetectMQTTReasonCodeSetup;
sigmatch_table[DETECT_AL_MQTT_REASON_CODE].Free = DetectMQTTReasonCodeFree;
#ifdef UNITTESTS
sigmatch_table[DETECT_AL_MQTT_REASON_CODE].RegisterTests = MQTTReasonCodeRegisterTests;
#endif
DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
DetectAppLayerInspectEngineRegister("mqtt.reason_code", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1,
DetectEngineInspectGenericList, NULL);
mqtt_reason_code_id = DetectBufferTypeGetByName("mqtt.reason_code");
}
/**
* \internal
* \brief Function to match reason code of an MQTT 5.0 Tx
*
* \param det_ctx Pointer to the pattern matcher thread.
* \param f Pointer to the current flow.
* \param flags Flags.
* \param state App layer state.
* \param txv Pointer to the transaction.
* \param s Pointer to the Signature.
* \param ctx Pointer to the sigmatch that we will cast into DetectMQTTReasonCodeData.
*
* \retval 0 no match.
* \retval 1 match.
*/
static int DetectMQTTReasonCodeMatch(DetectEngineThreadCtx *det_ctx,
Flow *f, uint8_t flags, void *state,
void *txv, const Signature *s,
const SigMatchCtx *ctx)
{
const uint8_t *de = (const uint8_t *)ctx;
uint8_t code;
if (!de)
return 0;
if (rs_mqtt_tx_get_reason_code(txv, &code) == 0) {
/* this function does not return a code that needs to be compared,
so we can just return the result of the check implemented in
Rust */
return rs_mqtt_tx_unsuback_has_reason_code(txv, *de);
} else {
if (code == *de)
return 1;
}
return 0;
}
/**
* \internal
* \brief This function is used to parse options passed via mqtt.reason_code: keyword
*
* \param rawstr Pointer to the user provided options
*
* \retval de pointer to DetectMQTTReasonCodeData on success
* \retval NULL on failure
*/
static uint8_t *DetectMQTTReasonCodeParse(const char *rawstr)
{
uint8_t *de = NULL;
int ret = 0;
uint8_t val;
ret = StringParseUint8(&val, 10, 0, rawstr);
if (ret < 0) {
SCLogError("invalid MQTT reason code: %s", rawstr);
return NULL;
}
de = SCMalloc(sizeof(uint8_t));
if (unlikely(de == NULL))
return NULL;
*de = (uint8_t) val;
return de;
}
/**
* \internal
* \brief this function is used to add the parsed sigmatch into the current signature
*
* \param de_ctx pointer to the Detection Engine Context
* \param s pointer to the Current Signature
* \param rawstr pointer to the user provided options
*
* \retval 0 on Success
* \retval -1 on Failure
*/
static int DetectMQTTReasonCodeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
{
uint8_t *de = NULL;
if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0)
return -1;
de = DetectMQTTReasonCodeParse(rawstr);
if (de == NULL)
goto error;
if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_REASON_CODE, (SigMatchCtx *)de,
mqtt_reason_code_id) == NULL) {
goto error;
}
return 0;
error:
if (de != NULL)
SCFree(de);
return -1;
}
/**
* \internal
* \brief this function will free memory associated with DetectMQTTReasonCodeData
*
* \param de pointer to DetectMQTTReasonCodeData
*/
void DetectMQTTReasonCodeFree(DetectEngineCtx *de_ctx, void *de_ptr)
{
if (de_ptr != NULL)
SCFree(de_ptr);
}
/*
* ONLY TESTS BELOW THIS COMMENT
*/
#ifdef UNITTESTS
/**
* \test MQTTReasonCodeTestParse01 is a test for a valid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTReasonCodeTestParse01 (void)
{
uint8_t *de = NULL;
de = DetectMQTTReasonCodeParse("3");
FAIL_IF_NULL(de);
FAIL_IF_NOT(*de == 3);
DetectMQTTReasonCodeFree(NULL, de);
de = DetectMQTTReasonCodeParse(" 4");
FAIL_IF_NULL(de);
FAIL_IF_NOT(*de == 4);
DetectMQTTReasonCodeFree(NULL, de);
de = DetectMQTTReasonCodeParse(" 5");
FAIL_IF_NULL(de);
FAIL_IF_NOT(*de == 5);
DetectMQTTReasonCodeFree(NULL, de);
de = DetectMQTTReasonCodeParse("255");
FAIL_IF_NULL(de);
FAIL_IF_NOT(*de == 255);
DetectMQTTReasonCodeFree(NULL, de);
PASS;
}
/**
* \test MQTTReasonCodeTestParse02 is a test for an invalid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTReasonCodeTestParse02 (void)
{
uint8_t *de = NULL;
de = DetectMQTTReasonCodeParse("6X");
if (de) {
DetectMQTTReasonCodeFree(NULL, de);
FAIL;
}
PASS;
}
/**
* \test MQTTReasonCodeTestParse03 is a test for an invalid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTReasonCodeTestParse03 (void)
{
uint8_t *de = NULL;
de = DetectMQTTReasonCodeParse("");
if (de) {
DetectMQTTReasonCodeFree(NULL, de);
FAIL;
}
PASS;
}
/**
* \test MQTTReasonCodeTestParse04 is a test for an invalid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTReasonCodeTestParse04 (void)
{
uint8_t *de = NULL;
de = DetectMQTTReasonCodeParse("256");
if (de) {
DetectMQTTReasonCodeFree(NULL, de);
FAIL;
}
PASS;
}
#endif /* UNITTESTS */
/**
* \brief this function registers unit tests for MQTTReasonCode
*/
void MQTTReasonCodeRegisterTests(void)
{
#ifdef UNITTESTS
UtRegisterTest("MQTTReasonCodeTestParse01", MQTTReasonCodeTestParse01);
UtRegisterTest("MQTTReasonCodeTestParse02", MQTTReasonCodeTestParse02);
UtRegisterTest("MQTTReasonCodeTestParse03", MQTTReasonCodeTestParse03);
UtRegisterTest("MQTTReasonCodeTestParse04", MQTTReasonCodeTestParse04);
#endif /* UNITTESTS */
}

@ -1,29 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#ifndef SURICATA_DETECT_MQTT_REASON_CODE_H
#define SURICATA_DETECT_MQTT_REASON_CODE_H
void DetectMQTTReasonCodeRegister(void);
#endif /* SURICATA_DETECT_MQTT_REASON_CODE_H */

@ -1,142 +0,0 @@
/* Copyright (C) 2020-2022 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#include "suricata-common.h"
#include "app-layer.h"
#include "app-layer-parser.h"
#include "conf.h"
#include "decode.h"
#include "detect.h"
#include "detect-content.h"
#include "detect-parse.h"
#include "detect-pcre.h"
#include "detect-engine.h"
#include "detect-engine-content-inspection.h"
#include "detect-engine-mpm.h"
#include "detect-engine-prefilter.h"
#include "detect-mqtt-subscribe-topic.h"
#include "util-unittest.h"
#include "util-unittest-helper.h"
#include "rust-bindings.h"
#include "threads.h"
#include "flow.h"
#include "flow-util.h"
#include "flow-var.h"
#include "util-debug.h"
#include "util-spm.h"
#include "util-print.h"
#include "util-profiling.h"
static int DetectMQTTSubscribeTopicSetup(DetectEngineCtx *, Signature *, const char *);
static int g_mqtt_subscribe_topic_buffer_id = 0;
static uint32_t subscribe_topic_match_limit = 100;
static InspectionBuffer *MQTTSubscribeTopicGetData(DetectEngineThreadCtx *det_ctx,
const DetectEngineTransforms *transforms, Flow *f, const uint8_t flags, void *txv,
int list_id, uint32_t local_id)
{
SCEnter();
if (subscribe_topic_match_limit > 0 && local_id >= subscribe_topic_match_limit)
return NULL;
InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, list_id, local_id);
if (buffer == NULL)
return NULL;
if (buffer->initialized)
return buffer;
const uint8_t *data;
uint32_t data_len;
if (rs_mqtt_tx_get_subscribe_topic(txv, local_id, &data, &data_len) == 0) {
InspectionBufferSetupMultiEmpty(buffer);
return NULL;
}
InspectionBufferSetupMulti(buffer, transforms, data, data_len);
buffer->flags = DETECT_CI_FLAGS_SINGLE;
SCReturnPtr(buffer, "InspectionBuffer");
}
/**
* \brief Registration function for keyword: mqtt.subscribe.topic
*/
void DetectMQTTSubscribeTopicRegister (void)
{
sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].name = "mqtt.subscribe.topic";
sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].desc = "sticky buffer to match MQTT SUBSCRIBE topic";
sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].url = "/rules/mqtt-keywords.html#mqtt-subscribe-topic";
sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].Setup = DetectMQTTSubscribeTopicSetup;
sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].flags |= SIGMATCH_NOOPT;
sigmatch_table[DETECT_AL_MQTT_SUBSCRIBE_TOPIC].flags |= SIGMATCH_INFO_STICKY_BUFFER;
intmax_t val = 0;
if (ConfGetInt("app-layer.protocols.mqtt.subscribe-topic-match-limit", &val)) {
subscribe_topic_match_limit = val;
}
if (subscribe_topic_match_limit <= 0) {
SCLogDebug("Using unrestricted MQTT SUBSCRIBE topic matching");
} else {
SCLogDebug("Using MQTT SUBSCRIBE topic match-limit setting of: %u",
subscribe_topic_match_limit);
}
DetectAppLayerMultiRegister("mqtt.subscribe.topic", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1,
MQTTSubscribeTopicGetData, 1, 1);
DetectBufferTypeSetDescriptionByName("mqtt.subscribe.topic",
"subscribe topic query");
g_mqtt_subscribe_topic_buffer_id = DetectBufferTypeGetByName("mqtt.subscribe.topic");
DetectBufferTypeSupportsMultiInstance("mqtt.subscribe.topic");
}
/**
* \brief setup the sticky buffer keyword used in the rule
*
* \param de_ctx Pointer to the Detection Engine Context
* \param s Pointer to the Signature to which the current keyword belongs
* \param str Should hold an empty string always
*
* \retval 0 On success
* \retval -1 On failure
*/
static int DetectMQTTSubscribeTopicSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
{
if (DetectBufferSetActiveList(de_ctx, s, g_mqtt_subscribe_topic_buffer_id) < 0)
return -1;
if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0)
return -1;
return 0;
}

@ -1,29 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#ifndef SURICATA_DETECT_MQTT_SUBSCRIBE_TOPIC_H
#define SURICATA_DETECT_MQTT_SUBSCRIBE_TOPIC_H
void DetectMQTTSubscribeTopicRegister(void);
#endif /* SURICATA_DETECT_MQTT_SUBSCRIBE_TOPIC_H */

@ -1,256 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#include "suricata-common.h"
#include "conf.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-engine.h"
#include "detect-engine-content-inspection.h"
#include "detect-mqtt-type.h"
#include "util-unittest.h"
#include "rust.h"
static int mqtt_type_id = 0;
static int DetectMQTTTypeMatch(DetectEngineThreadCtx *det_ctx,
Flow *f, uint8_t flags, void *state,
void *txv, const Signature *s,
const SigMatchCtx *ctx);
static int DetectMQTTTypeSetup (DetectEngineCtx *, Signature *, const char *);
void MQTTTypeRegisterTests(void);
void DetectMQTTTypeFree(DetectEngineCtx *de_ctx, void *);
/**
* \brief Registration function for mqtt.type: keyword
*/
void DetectMQTTTypeRegister (void)
{
sigmatch_table[DETECT_AL_MQTT_TYPE].name = "mqtt.type";
sigmatch_table[DETECT_AL_MQTT_TYPE].desc = "match MQTT control packet type";
sigmatch_table[DETECT_AL_MQTT_TYPE].url = "/rules/mqtt-keywords.html#mqtt-type";
sigmatch_table[DETECT_AL_MQTT_TYPE].AppLayerTxMatch = DetectMQTTTypeMatch;
sigmatch_table[DETECT_AL_MQTT_TYPE].Setup = DetectMQTTTypeSetup;
sigmatch_table[DETECT_AL_MQTT_TYPE].Free = DetectMQTTTypeFree;
#ifdef UNITTESTS
sigmatch_table[DETECT_AL_MQTT_TYPE].RegisterTests = MQTTTypeRegisterTests;
#endif
DetectAppLayerInspectEngineRegister(
"mqtt.type", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL);
mqtt_type_id = DetectBufferTypeGetByName("mqtt.type");
}
/**
* \internal
* \brief Function to match control packet type of an MQTT Tx
*
* \param det_ctx Pointer to the pattern matcher thread.
* \param f Pointer to the current flow.
* \param flags Flags.
* \param state App layer state.
* \param txv Pointer to the transaction.
* \param s Pointer to the Signature.
* \param ctx Pointer to the sigmatch that we will cast into DetectMQTTTypeData.
*
* \retval 0 no match.
* \retval 1 match.
*/
static int DetectMQTTTypeMatch(DetectEngineThreadCtx *det_ctx,
Flow *f, uint8_t flags, void *state,
void *txv, const Signature *s,
const SigMatchCtx *ctx)
{
const uint8_t *de = (const uint8_t *)ctx;
if (!de)
return 0;
return rs_mqtt_tx_has_type(txv, *de);
}
/**
* \internal
* \brief This function is used to parse options passed via mqtt.type: keyword
*
* \param rawstr Pointer to the user provided options
*
* \retval de pointer to DetectMQTTTypeData on success
* \retval NULL on failure
*/
static uint8_t *DetectMQTTTypeParse(const char *rawstr)
{
uint8_t *de = NULL;
int ret = 0;
ret = rs_mqtt_cstr_message_code(rawstr);
// negative value denotes invalid input
if(ret < 0) {
SCLogError("unknown mqtt.type value %s", rawstr);
goto error;
}
de = SCMalloc(sizeof(uint8_t));
if (unlikely(de == NULL))
goto error;
*de = (uint8_t) ret;
return de;
error:
if (de != NULL)
SCFree(de);
return NULL;
}
/**
* \internal
* \brief this function is used to add the parsed type query into the current signature
*
* \param de_ctx pointer to the Detection Engine Context
* \param s pointer to the Current Signature
* \param rawstr pointer to the user provided options
*
* \retval 0 on Success
* \retval -1 on Failure
*/
static int DetectMQTTTypeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
{
uint8_t *de = NULL;
if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0)
return -1;
de = DetectMQTTTypeParse(rawstr);
if (de == NULL)
goto error;
if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_MQTT_TYPE, (SigMatchCtx *)de, mqtt_type_id) ==
NULL) {
goto error;
}
return 0;
error:
if (de != NULL)
SCFree(de);
return -1;
}
/**
* \internal
* \brief this function will free memory associated with DetectMQTTTypeData
*
* \param de pointer to DetectMQTTTypeData
*/
void DetectMQTTTypeFree(DetectEngineCtx *de_ctx, void *de_ptr)
{
if (de_ptr != NULL)
SCFree(de_ptr);
}
/*
* ONLY TESTS BELOW THIS COMMENT
*/
#ifdef UNITTESTS
/**
* \test MQTTTypeTestParse01 is a test for a valid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTTypeTestParse01 (void)
{
uint8_t *de = NULL;
de = DetectMQTTTypeParse("CONNECT");
FAIL_IF_NULL(de);
FAIL_IF_NOT(*de == 1);
DetectMQTTTypeFree(NULL, de);
de = DetectMQTTTypeParse("PINGRESP");
FAIL_IF_NULL(de);
FAIL_IF_NOT(*de == 13);
DetectMQTTTypeFree(NULL, de);
PASS;
}
/**
* \test MQTTTypeTestParse02 is a test for a valid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTTypeTestParse02 (void)
{
uint8_t *de = NULL;
de = DetectMQTTTypeParse("auth");
FAIL_IF_NULL(de);
FAIL_IF_NOT(*de == 15);
DetectMQTTTypeFree(NULL, de);
PASS;
}
/**
* \test MQTTTypeTestParse03 is a test for an invalid value
*
* \retval 1 on success
* \retval 0 on failure
*/
static int MQTTTypeTestParse03 (void)
{
uint8_t *de = NULL;
de = DetectMQTTTypeParse("invalidopt");
if (de) {
DetectMQTTTypeFree(NULL, de);
FAIL;
}
de = DetectMQTTTypeParse("unassigned");
if (de) {
DetectMQTTTypeFree(NULL, de);
FAIL;
}
PASS;
}
#endif /* UNITTESTS */
/**
* \brief this function registers unit tests for MQTTType
*/
void MQTTTypeRegisterTests(void)
{
#ifdef UNITTESTS
UtRegisterTest("MQTTTypeTestParse01", MQTTTypeTestParse01);
UtRegisterTest("MQTTTypeTestParse02", MQTTTypeTestParse02);
UtRegisterTest("MQTTTypeTestParse03", MQTTTypeTestParse03);
#endif /* UNITTESTS */
}

@ -1,29 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#ifndef SURICATA_DETECT_MQTT_TYPE_H
#define SURICATA_DETECT_MQTT_TYPE_H
void DetectMQTTTypeRegister(void);
#endif /* SURICATA_DETECT_MQTT_TYPE_H */

@ -1,142 +0,0 @@
/* Copyright (C) 2020-2022 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#include "suricata-common.h"
#include "app-layer.h"
#include "app-layer-parser.h"
#include "conf.h"
#include "decode.h"
#include "detect.h"
#include "detect-content.h"
#include "detect-parse.h"
#include "detect-pcre.h"
#include "detect-engine.h"
#include "detect-engine-content-inspection.h"
#include "detect-engine-mpm.h"
#include "detect-engine-prefilter.h"
#include "detect-mqtt-unsubscribe-topic.h"
#include "util-unittest.h"
#include "util-unittest-helper.h"
#include "rust-bindings.h"
#include "threads.h"
#include "flow.h"
#include "flow-util.h"
#include "flow-var.h"
#include "util-debug.h"
#include "util-spm.h"
#include "util-print.h"
#include "util-profiling.h"
static int DetectMQTTUnsubscribeTopicSetup(DetectEngineCtx *, Signature *, const char *);
static int g_mqtt_unsubscribe_topic_buffer_id = 0;
static uint32_t unsubscribe_topic_match_limit = 100;
static InspectionBuffer *MQTTUnsubscribeTopicGetData(DetectEngineThreadCtx *det_ctx,
const DetectEngineTransforms *transforms, Flow *f, const uint8_t flags, void *txv,
int list_id, uint32_t local_id)
{
SCEnter();
if (unsubscribe_topic_match_limit > 0 && local_id >= unsubscribe_topic_match_limit)
return NULL;
InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, list_id, local_id);
if (buffer == NULL)
return NULL;
if (buffer->initialized)
return buffer;
const uint8_t *data;
uint32_t data_len;
if (rs_mqtt_tx_get_unsubscribe_topic(txv, local_id, &data, &data_len) == 0) {
InspectionBufferSetupMultiEmpty(buffer);
return NULL;
}
InspectionBufferSetupMulti(buffer, transforms, data, data_len);
buffer->flags = DETECT_CI_FLAGS_SINGLE;
SCReturnPtr(buffer, "InspectionBuffer");
}
/**
* \brief Registration function for keyword: mqtt.unsubscribe.topic
*/
void DetectMQTTUnsubscribeTopicRegister (void)
{
sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].name = "mqtt.unsubscribe.topic";
sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].desc = "sticky buffer to match MQTT UNSUBSCRIBE topic";
sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].url = "/rules/mqtt-keywords.html#mqtt-unsubscribe-topic";
sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].Setup = DetectMQTTUnsubscribeTopicSetup;
sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].flags |= SIGMATCH_NOOPT;
sigmatch_table[DETECT_AL_MQTT_UNSUBSCRIBE_TOPIC].flags |= SIGMATCH_INFO_STICKY_BUFFER;
intmax_t val = 0;
if (ConfGetInt("app-layer.protocols.mqtt.unsubscribe-topic-match-limit", &val)) {
unsubscribe_topic_match_limit = val;
}
if (unsubscribe_topic_match_limit <= 0) {
SCLogDebug("Using unrestricted MQTT UNSUBSCRIBE topic matching");
} else {
SCLogDebug("Using MQTT UNSUBSCRIBE topic match-limit setting of: %i",
unsubscribe_topic_match_limit);
}
DetectAppLayerMultiRegister("mqtt.unsubscribe.topic", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1,
MQTTUnsubscribeTopicGetData, 1, 1);
DetectBufferTypeSetDescriptionByName("mqtt.unsubscribe.topic",
"unsubscribe topic query");
g_mqtt_unsubscribe_topic_buffer_id = DetectBufferTypeGetByName("mqtt.unsubscribe.topic");
DetectBufferTypeSupportsMultiInstance("mqtt.unsubscribe.topic");
}
/**
* \brief setup the sticky buffer keyword used in the rule
*
* \param de_ctx Pointer to the Detection Engine Context
* \param s Pointer to the Signature to which the current keyword belongs
* \param str Should hold an empty string always
*
* \retval 0 On success
* \retval -1 On failure
*/
static int DetectMQTTUnsubscribeTopicSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
{
if (DetectBufferSetActiveList(de_ctx, s, g_mqtt_unsubscribe_topic_buffer_id) < 0)
return -1;
if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0)
return -1;
return 0;
}

@ -1,29 +0,0 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha@steinbiss.name>
*/
#ifndef SURICATA_DETECT_MQTT_UNSUBSCRIBE_TOPIC_H
#define SURICATA_DETECT_MQTT_UNSUBSCRIBE_TOPIC_H
void DetectMQTTUnsubscribeTopicRegister(void);
#endif /* SURICATA_DETECT_MQTT_UNSUBSCRIBE_TOPIC_H */
Loading…
Cancel
Save