mirror of https://github.com/OISF/suricata
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
parent
f4e7d1e217
commit
0a1062fad2
File diff suppressed because it is too large
Load Diff
@ -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…
Reference in New Issue