/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 | } |