Coverage Report

Created: 2025-12-31 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/detect-mqtt-connack-sessionpresent.c
Line
Count
Source
1
/* Copyright (C) 2020 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17
18
/**
19
 * \file
20
 *
21
 * \author Sascha Steinbiss <sascha@steinbiss.name>
22
 */
23
24
#include "suricata-common.h"
25
#include "conf.h"
26
#include "detect.h"
27
#include "detect-parse.h"
28
#include "detect-engine.h"
29
#include "detect-engine-content-inspection.h"
30
#include "detect-mqtt-connack-sessionpresent.h"
31
#include "util-unittest.h"
32
33
#include "rust.h"
34
35
34
#define PARSE_REGEX "^true|false|yes|no$"
36
static DetectParseRegex parse_regex;
37
38
static int mqtt_connack_session_present_id = 0;
39
40
static int DetectMQTTConnackSessionPresentMatch(DetectEngineThreadCtx *det_ctx,
41
                               Flow *f, uint8_t flags, void *state,
42
                               void *txv, const Signature *s,
43
                               const SigMatchCtx *ctx);
44
static int DetectMQTTConnackSessionPresentSetup (DetectEngineCtx *, Signature *, const char *);
45
void MQTTConnackSessionPresentRegisterTests(void);
46
void DetectMQTTConnackSessionPresentFree(DetectEngineCtx *de_ctx, void *);
47
48
/**
49
 * \brief Registration function for mqtt.connack.session_present: keyword
50
 */
51
void DetectMQTTConnackSessionPresentRegister (void)
52
34
{
53
34
    sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].name = "mqtt.connack.session_present";
54
34
    sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].desc = "match MQTT CONNACK session present flag";
55
34
    sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].url = "/rules/mqtt-keywords.html#mqtt-connack-session-present";
56
34
    sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].AppLayerTxMatch = DetectMQTTConnackSessionPresentMatch;
57
34
    sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].Setup = DetectMQTTConnackSessionPresentSetup;
58
34
    sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].Free  = DetectMQTTConnackSessionPresentFree;
59
#ifdef UNITTESTS
60
    sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].RegisterTests = MQTTConnackSessionPresentRegisterTests;
61
#endif
62
63
34
    DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
64
65
34
    DetectAppLayerInspectEngineRegister2("mqtt.connack.session_present", ALPROTO_MQTT,
66
34
            SIG_FLAG_TOCLIENT, 1, DetectEngineInspectGenericList, NULL);
67
68
34
    mqtt_connack_session_present_id = DetectBufferTypeGetByName("mqtt.connack.session_present");
69
34
}
70
71
/**
72
 * \internal
73
 * \brief Function to match session_present flag of an MQTT CONNACK message
74
 *
75
 * \param det_ctx Pointer to the pattern matcher thread.
76
 * \param f       Pointer to the current flow.
77
 * \param flags   Flags.
78
 * \param state   App layer state.
79
 * \param txv     Pointer to the transaction.
80
 * \param s       Pointer to the Signature.
81
 * \param ctx     Pointer to the sigmatch that we will cast into DetectMQTTConnackSessionPresentData.
82
 *
83
 * \retval 0 no match.
84
 * \retval 1 match.
85
 */
86
static int DetectMQTTConnackSessionPresentMatch(DetectEngineThreadCtx *det_ctx,
87
                               Flow *f, uint8_t flags, void *state,
88
                               void *txv, const Signature *s,
89
                               const SigMatchCtx *ctx)
90
0
{
91
0
    const bool *de = (const bool *)ctx;
92
0
    bool value = false;
93
94
0
    if (!de)
95
0
        return 0;
96
97
0
    if (rs_mqtt_tx_get_connack_sessionpresent(txv, &value) ==0 ) {
98
0
        return 0;
99
0
    }
100
0
    if (value != *de) {
101
0
        return 0;
102
0
    }
103
104
0
    return 1;
105
0
}
106
107
/**
108
 * \internal
109
 * \brief This function is used to parse options passed via mqtt.connack.session_present: keyword
110
 *
111
 * \param rawstr Pointer to the user provided options
112
 *
113
 * \retval de pointer to DetectMQTTConnackSessionPresentData on success
114
 * \retval NULL on failure
115
 */
116
static bool *DetectMQTTConnackSessionPresentParse(const char *rawstr)
117
27
{
118
27
    bool *de = NULL;
119
27
    de = SCMalloc(sizeof(bool));
120
27
    if (unlikely(de == NULL))
121
0
        return NULL;
122
27
    *de = false;
123
124
27
    if (strcmp(rawstr, "yes") == 0) {
125
0
        *de = true;
126
27
    } else if (strcmp(rawstr, "true") == 0) {
127
0
        *de = true;
128
27
    } else if (strcmp(rawstr, "no") == 0) {
129
0
        *de = false;
130
27
    } else if (strcmp(rawstr, "false") == 0) {
131
0
        *de = false;
132
27
    } else {
133
27
        SCLogError("invalid session_present flag definition: %s", rawstr);
134
27
        goto error;
135
27
    }
136
137
0
    return de;
138
139
27
error:
140
    /* de can't be NULL here */
141
27
    SCFree(de);
142
27
    return NULL;
143
27
}
144
145
/**
146
 * \internal
147
 * \brief this function is used to add the parsed type query into the current signature
148
 *
149
 * \param de_ctx pointer to the Detection Engine Context
150
 * \param s pointer to the Current Signature
151
 * \param rawstr pointer to the user provided options
152
 *
153
 * \retval 0 on Success
154
 * \retval -1 on Failure
155
 */
156
static int DetectMQTTConnackSessionPresentSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
157
78
{
158
78
    bool *de = NULL;
159
78
    SigMatch *sm = NULL;
160
161
78
    if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0)
162
51
        return -1;
163
164
27
    de = DetectMQTTConnackSessionPresentParse(rawstr);
165
27
    if (de == NULL)
166
27
        goto error;
167
168
0
    sm = SigMatchAlloc();
169
0
    if (sm == NULL)
170
0
        goto error;
171
172
0
    sm->type = DETECT_AL_MQTT_CONNACK_SESSION_PRESENT;
173
0
    sm->ctx = (SigMatchCtx *)de;
174
175
0
    SigMatchAppendSMToList(s, sm, mqtt_connack_session_present_id);
176
177
0
    return 0;
178
179
27
error:
180
27
    if (de != NULL)
181
0
        SCFree(de);
182
27
    if (sm != NULL)
183
0
        SCFree(sm);
184
27
    return -1;
185
0
}
186
187
/**
188
 * \internal
189
 * \brief this function will free memory associated with DetectMQTTConnackSessionPresentData
190
 *
191
 * \param de pointer to DetectMQTTConnackSessionPresentData
192
 */
193
void DetectMQTTConnackSessionPresentFree(DetectEngineCtx *de_ctx, void *de_ptr)
194
0
{
195
0
    if (de_ptr != NULL)
196
0
        SCFree(de_ptr);
197
0
}
198
199
/*
200
 * ONLY TESTS BELOW THIS COMMENT
201
 */
202
203
#ifdef UNITTESTS
204
/**
205
 * \test MQTTConnackSessionPresentTestParse01 is a test for a valid value
206
 *
207
 *  \retval 1 on success
208
 *  \retval 0 on failure
209
 */
210
static int MQTTConnackSessionPresentTestParse01 (void)
211
{
212
    bool *de = NULL;
213
214
    de = DetectMQTTConnackSessionPresentParse("yes");
215
    FAIL_IF_NULL(de);
216
    DetectMQTTConnackSessionPresentFree(NULL, de);
217
218
    de = DetectMQTTConnackSessionPresentParse("true");
219
    FAIL_IF_NULL(de);
220
    DetectMQTTConnackSessionPresentFree(NULL, de);
221
222
    de = DetectMQTTConnackSessionPresentParse("false");
223
    FAIL_IF_NULL(de);
224
    DetectMQTTConnackSessionPresentFree(NULL, de);
225
226
    de = DetectMQTTConnackSessionPresentParse("no");
227
    FAIL_IF_NULL(de);
228
    DetectMQTTConnackSessionPresentFree(NULL, de);
229
230
    PASS;
231
}
232
233
/**
234
 * \test MQTTConnackSessionPresentTestParse02 is a test for an invalid value
235
 *
236
 *  \retval 1 on success
237
 *  \retval 0 on failure
238
 */
239
static int MQTTConnackSessionPresentTestParse02 (void)
240
{
241
    bool *de = NULL;
242
    de = DetectMQTTConnackSessionPresentParse("nix");
243
    if (de) {
244
        DetectMQTTConnackSessionPresentFree(NULL, de);
245
        FAIL;
246
    }
247
248
    PASS;
249
}
250
251
/**
252
 * \test MQTTConnackSessionPresentTestParse03 is a test for an invalid value
253
 *
254
 *  \retval 1 on success
255
 *  \retval 0 on failure
256
 */
257
static int MQTTConnackSessionPresentTestParse03 (void)
258
{
259
    bool *de = NULL;
260
    de = DetectMQTTConnackSessionPresentParse("");
261
    if (de) {
262
        DetectMQTTConnackSessionPresentFree(NULL, de);
263
        FAIL;
264
    }
265
266
    PASS;
267
}
268
269
/**
270
 * \test MQTTConnackSessionPresentTestParse04 is a test for an invalid value
271
 *
272
 *  \retval 1 on success
273
 *  \retval 0 on failure
274
 */
275
static int MQTTConnackSessionPresentTestParse04 (void)
276
{
277
    bool *de = NULL;
278
    de = DetectMQTTConnackSessionPresentParse(",");
279
    if (de) {
280
        DetectMQTTConnackSessionPresentFree(NULL, de);
281
        FAIL;
282
    }
283
284
    PASS;
285
}
286
287
288
#endif /* UNITTESTS */
289
290
/**
291
 * \brief this function registers unit tests for MQTTConnackSessionPresent
292
 */
293
void MQTTConnackSessionPresentRegisterTests(void)
294
0
{
295
#ifdef UNITTESTS
296
    UtRegisterTest("MQTTConnackSessionPresentTestParse01", MQTTConnackSessionPresentTestParse01);
297
    UtRegisterTest("MQTTConnackSessionPresentTestParse02", MQTTConnackSessionPresentTestParse02);
298
    UtRegisterTest("MQTTConnackSessionPresentTestParse03", MQTTConnackSessionPresentTestParse03);
299
    UtRegisterTest("MQTTConnackSessionPresentTestParse04", MQTTConnackSessionPresentTestParse04);
300
#endif /* UNITTESTS */
301
0
}