]> git.ipfire.org Git - people/ms/suricata.git/blame - src/detect-mqtt-connack-sessionpresent.c
detect-mqtt: unify error handling in rule parsing
[people/ms/suricata.git] / src / detect-mqtt-connack-sessionpresent.c
CommitLineData
c3136007
SS
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-bindings.h"
34
35#define PARSE_REGEX "^true|false|yes|no$"
36static DetectParseRegex parse_regex;
37
38static int mqtt_connack_session_present_id = 0;
39
40static int DetectMQTTConnackSessionPresentMatch(DetectEngineThreadCtx *det_ctx,
41 Flow *f, uint8_t flags, void *state,
42 void *txv, const Signature *s,
43 const SigMatchCtx *ctx);
44static int DetectMQTTConnackSessionPresentSetup (DetectEngineCtx *, Signature *, const char *);
45void MQTTConnackSessionPresentRegisterTests(void);
46void DetectMQTTConnackSessionPresentFree(DetectEngineCtx *de_ctx, void *);
47
48static int DetectEngineInspectMQTTConnackSessionPresentGeneric(ThreadVars *tv,
49 DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
50 const Signature *s, const SigMatchData *smd,
51 Flow *f, uint8_t flags, void *alstate,
52 void *txv, uint64_t tx_id);
53
54/**
55 * \brief Registration function for mqtt.connack.session_present: keyword
56 */
57void DetectMQTTConnackSessionPresentRegister (void)
58{
59 sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].name = "mqtt.connack.session_present";
60 sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].desc = "match MQTT CONNACK session present flag";
61 sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].url = "/rules/mqtt-keywords.html#mqtt-connack-session-present";
62 sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].AppLayerTxMatch = DetectMQTTConnackSessionPresentMatch;
63 sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].Setup = DetectMQTTConnackSessionPresentSetup;
64 sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].Free = DetectMQTTConnackSessionPresentFree;
65#ifdef UNITTESTS
66 sigmatch_table[DETECT_AL_MQTT_CONNACK_SESSION_PRESENT].RegisterTests = MQTTConnackSessionPresentRegisterTests;
67#endif
68
69 DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
70
71 DetectAppLayerInspectEngineRegister("mqtt.connack.session_present",
72 ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1,
73 DetectEngineInspectMQTTConnackSessionPresentGeneric);
74
75 mqtt_connack_session_present_id = DetectBufferTypeGetByName("mqtt.connack.session_present");
76}
77
78static int DetectEngineInspectMQTTConnackSessionPresentGeneric(ThreadVars *tv,
79 DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
80 const Signature *s, const SigMatchData *smd,
81 Flow *f, uint8_t flags, void *alstate,
82 void *txv, uint64_t tx_id)
83{
84 return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd,
85 f, flags, alstate, txv, tx_id);
86}
87
88/**
89 * \internal
90 * \brief Function to match session_present flag of an MQTT CONNACK message
91 *
92 * \param det_ctx Pointer to the pattern matcher thread.
93 * \param f Pointer to the current flow.
94 * \param flags Flags.
95 * \param state App layer state.
96 * \param txv Pointer to the transaction.
97 * \param s Pointer to the Signature.
98 * \param ctx Pointer to the sigmatch that we will cast into DetectMQTTConnackSessionPresentData.
99 *
100 * \retval 0 no match.
101 * \retval 1 match.
102 */
103static int DetectMQTTConnackSessionPresentMatch(DetectEngineThreadCtx *det_ctx,
104 Flow *f, uint8_t flags, void *state,
105 void *txv, const Signature *s,
106 const SigMatchCtx *ctx)
107{
108 const bool *de = (const bool *)ctx;
109 bool value = false;
110
111 if (!de)
112 return 0;
113
114 if (rs_mqtt_tx_get_connack_sessionpresent(txv, &value) ==0 ) {
115 return 0;
116 }
117 if (value != *de) {
118 return 0;
119 }
120
121 return 1;
122}
123
124/**
125 * \internal
126 * \brief This function is used to parse options passed via mqtt.connack.session_present: keyword
127 *
128 * \param rawstr Pointer to the user provided options
129 *
130 * \retval de pointer to DetectMQTTConnackSessionPresentData on success
131 * \retval NULL on failure
132 */
133static bool *DetectMQTTConnackSessionPresentParse(const char *rawstr)
134{
135 bool *de = NULL;
136 de = SCMalloc(sizeof(bool));
137 if (unlikely(de == NULL))
138 return NULL;
139 *de = false;
140
141 if (strcmp(rawstr, "yes") == 0) {
142 *de = true;
143 } else if (strcmp(rawstr, "true") == 0) {
144 *de = true;
145 } else if (strcmp(rawstr, "no") == 0) {
146 *de = false;
147 } else if (strcmp(rawstr, "false") == 0) {
148 *de = false;
149 } else {
150 SCLogError(SC_ERR_UNKNOWN_VALUE, "invalid session_present flag definition: %s", rawstr);
151 goto error;
152 }
153
154 return de;
155
156error:
93eef1da
SS
157 /* de can't be NULL here */
158 SCFree(de);
c3136007
SS
159 return NULL;
160}
161
162/**
163 * \internal
164 * \brief this function is used to add the parsed type query into the current signature
165 *
166 * \param de_ctx pointer to the Detection Engine Context
167 * \param s pointer to the Current Signature
168 * \param rawstr pointer to the user provided options
169 *
170 * \retval 0 on Success
171 * \retval -1 on Failure
172 */
173static int DetectMQTTConnackSessionPresentSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
174{
175 bool *de = NULL;
176 SigMatch *sm = NULL;
177
178 if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0)
179 return -1;
180
181 de = DetectMQTTConnackSessionPresentParse(rawstr);
182 if (de == NULL)
183 goto error;
184
185 sm = SigMatchAlloc();
186 if (sm == NULL)
187 goto error;
188
189 sm->type = DETECT_AL_MQTT_CONNACK_SESSION_PRESENT;
190 sm->ctx = (SigMatchCtx *)de;
191
192 SigMatchAppendSMToList(s, sm, mqtt_connack_session_present_id);
193
194 return 0;
195
196error:
197 if (de != NULL)
198 SCFree(de);
199 if (sm != NULL)
200 SCFree(sm);
201 return -1;
202}
203
204/**
205 * \internal
206 * \brief this function will free memory associated with DetectMQTTConnackSessionPresentData
207 *
208 * \param de pointer to DetectMQTTConnackSessionPresentData
209 */
210void DetectMQTTConnackSessionPresentFree(DetectEngineCtx *de_ctx, void *de_ptr)
211{
212 if (de_ptr != NULL)
213 SCFree(de_ptr);
214}
215
216/*
217 * ONLY TESTS BELOW THIS COMMENT
218 */
219
220#ifdef UNITTESTS
221/**
222 * \test MQTTConnackSessionPresentTestParse01 is a test for a valid value
223 *
224 * \retval 1 on success
225 * \retval 0 on failure
226 */
227static int MQTTConnackSessionPresentTestParse01 (void)
228{
229 bool *de = NULL;
230
231 de = DetectMQTTConnackSessionPresentParse("yes");
232 FAIL_IF_NULL(de);
233 DetectMQTTConnackSessionPresentFree(NULL, de);
234
235 de = DetectMQTTConnackSessionPresentParse("true");
236 FAIL_IF_NULL(de);
237 DetectMQTTConnackSessionPresentFree(NULL, de);
238
239 de = DetectMQTTConnackSessionPresentParse("false");
240 FAIL_IF_NULL(de);
241 DetectMQTTConnackSessionPresentFree(NULL, de);
242
243 de = DetectMQTTConnackSessionPresentParse("no");
244 FAIL_IF_NULL(de);
245 DetectMQTTConnackSessionPresentFree(NULL, de);
246
247 PASS;
248}
249
250/**
251 * \test MQTTConnackSessionPresentTestParse02 is a test for an invalid value
252 *
253 * \retval 1 on success
254 * \retval 0 on failure
255 */
256static int MQTTConnackSessionPresentTestParse02 (void)
257{
258 bool *de = NULL;
259 de = DetectMQTTConnackSessionPresentParse("nix");
260 if (de) {
261 DetectMQTTConnackSessionPresentFree(NULL, de);
262 FAIL;
263 }
264
265 PASS;
266}
267
268/**
269 * \test MQTTConnackSessionPresentTestParse03 is a test for an invalid value
270 *
271 * \retval 1 on success
272 * \retval 0 on failure
273 */
274static int MQTTConnackSessionPresentTestParse03 (void)
275{
276 bool *de = NULL;
277 de = DetectMQTTConnackSessionPresentParse("");
278 if (de) {
279 DetectMQTTConnackSessionPresentFree(NULL, de);
280 FAIL;
281 }
282
283 PASS;
284}
285
286/**
287 * \test MQTTConnackSessionPresentTestParse04 is a test for an invalid value
288 *
289 * \retval 1 on success
290 * \retval 0 on failure
291 */
292static int MQTTConnackSessionPresentTestParse04 (void)
293{
294 bool *de = NULL;
295 de = DetectMQTTConnackSessionPresentParse(",");
296 if (de) {
297 DetectMQTTConnackSessionPresentFree(NULL, de);
298 FAIL;
299 }
300
301 PASS;
302}
303
304
305#endif /* UNITTESTS */
306
307/**
308 * \brief this function registers unit tests for MQTTConnackSessionPresent
309 */
310void MQTTConnackSessionPresentRegisterTests(void)
311{
312#ifdef UNITTESTS
313 UtRegisterTest("MQTTConnackSessionPresentTestParse01", MQTTConnackSessionPresentTestParse01);
314 UtRegisterTest("MQTTConnackSessionPresentTestParse02", MQTTConnackSessionPresentTestParse02);
315 UtRegisterTest("MQTTConnackSessionPresentTestParse03", MQTTConnackSessionPresentTestParse03);
316 UtRegisterTest("MQTTConnackSessionPresentTestParse04", MQTTConnackSessionPresentTestParse04);
317#endif /* UNITTESTS */
318}