/src/suricata7/src/detect-mqtt-qos.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-qos.h" |
31 | | #include "util-byte.h" |
32 | | #include "util-unittest.h" |
33 | | |
34 | | #include "rust.h" |
35 | | |
36 | | static int mqtt_qos_id = 0; |
37 | | |
38 | | static int DetectMQTTQosMatch(DetectEngineThreadCtx *det_ctx, |
39 | | Flow *f, uint8_t flags, void *state, |
40 | | void *txv, const Signature *s, |
41 | | const SigMatchCtx *ctx); |
42 | | static int DetectMQTTQosSetup (DetectEngineCtx *, Signature *, const char *); |
43 | | void MQTTQosRegisterTests(void); |
44 | | void DetectMQTTQosFree(DetectEngineCtx *de_ctx, void *); |
45 | | |
46 | | /** |
47 | | * \brief Registration function for mqtt.qos: keyword |
48 | | */ |
49 | | void DetectMQTTQosRegister (void) |
50 | 34 | { |
51 | 34 | sigmatch_table[DETECT_AL_MQTT_QOS].name = "mqtt.qos"; |
52 | 34 | sigmatch_table[DETECT_AL_MQTT_QOS].desc = "match MQTT fixed header QOS level"; |
53 | 34 | sigmatch_table[DETECT_AL_MQTT_QOS].url = "/rules/mqtt-keywords.html#mqtt-qos"; |
54 | 34 | sigmatch_table[DETECT_AL_MQTT_QOS].AppLayerTxMatch = DetectMQTTQosMatch; |
55 | 34 | sigmatch_table[DETECT_AL_MQTT_QOS].Setup = DetectMQTTQosSetup; |
56 | 34 | sigmatch_table[DETECT_AL_MQTT_QOS].Free = DetectMQTTQosFree; |
57 | | #ifdef UNITTESTS |
58 | | sigmatch_table[DETECT_AL_MQTT_QOS].RegisterTests = MQTTQosRegisterTests; |
59 | | #endif |
60 | | |
61 | 34 | DetectAppLayerInspectEngineRegister2( |
62 | 34 | "mqtt.qos", ALPROTO_MQTT, SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL); |
63 | | |
64 | 34 | mqtt_qos_id = DetectBufferTypeGetByName("mqtt.qos"); |
65 | 34 | } |
66 | | |
67 | | /** |
68 | | * \internal |
69 | | * \brief Function to match fixed header QOS field of an MQTT Tx |
70 | | * |
71 | | * \param det_ctx Pointer to the pattern matcher thread. |
72 | | * \param f Pointer to the current flow. |
73 | | * \param flags Flags. |
74 | | * \param state App layer state. |
75 | | * \param txv Pointer to the transaction. |
76 | | * \param s Pointer to the Signature. |
77 | | * \param ctx Pointer to the sigmatch that we will cast into uint8_t. |
78 | | * |
79 | | * \retval 0 no match. |
80 | | * \retval 1 match. |
81 | | */ |
82 | | static int DetectMQTTQosMatch(DetectEngineThreadCtx *det_ctx, |
83 | | Flow *f, uint8_t flags, void *state, |
84 | | void *txv, const Signature *s, |
85 | | const SigMatchCtx *ctx) |
86 | 6 | { |
87 | 6 | const uint8_t *de = (const uint8_t *)ctx; |
88 | | |
89 | 6 | if (!de) |
90 | 0 | return 0; |
91 | | |
92 | 6 | return rs_mqtt_tx_has_qos(txv, *de); |
93 | 6 | } |
94 | | |
95 | | /** |
96 | | * \internal |
97 | | * \brief This function is used to parse options passed via mqtt.qos: keyword |
98 | | * |
99 | | * \param rawstr Pointer to the user provided options |
100 | | * |
101 | | * \retval de pointer to DetectMQTTQosData on success |
102 | | * \retval NULL on failure |
103 | | */ |
104 | | static uint8_t *DetectMQTTQosParse(const char *rawstr) |
105 | 1.85k | { |
106 | 1.85k | uint8_t *de = NULL; |
107 | 1.85k | int ret = 0; |
108 | 1.85k | uint8_t val; |
109 | | |
110 | 1.85k | ret = StringParseU8RangeCheck(&val, 10, 0, rawstr, 0, 2); |
111 | 1.85k | if (ret <= 0) { |
112 | 173 | SCLogError("invalid MQTT QOS level: %s", rawstr); |
113 | 173 | return NULL; |
114 | 173 | } |
115 | | |
116 | 1.68k | de = SCMalloc(sizeof(uint8_t)); |
117 | 1.68k | if (unlikely(de == NULL)) |
118 | 0 | return NULL; |
119 | 1.68k | *de = val; |
120 | | |
121 | 1.68k | return de; |
122 | 1.68k | } |
123 | | |
124 | | /** |
125 | | * \internal |
126 | | * \brief this function is used to add the parsed sigmatch into the current signature |
127 | | * |
128 | | * \param de_ctx pointer to the Detection Engine Context |
129 | | * \param s pointer to the Current Signature |
130 | | * \param rawstr pointer to the user provided options |
131 | | * |
132 | | * \retval 0 on Success |
133 | | * \retval -1 on Failure |
134 | | */ |
135 | | static int DetectMQTTQosSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) |
136 | 1.87k | { |
137 | 1.87k | uint8_t *de = NULL; |
138 | 1.87k | SigMatch *sm = NULL; |
139 | | |
140 | 1.87k | if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) |
141 | 21 | return -1; |
142 | | |
143 | 1.85k | de = DetectMQTTQosParse(rawstr); |
144 | 1.85k | if (de == NULL) |
145 | 173 | goto error; |
146 | | |
147 | 1.68k | sm = SigMatchAlloc(); |
148 | 1.68k | if (sm == NULL) |
149 | 0 | goto error; |
150 | | |
151 | 1.68k | sm->type = DETECT_AL_MQTT_QOS; |
152 | 1.68k | sm->ctx = (SigMatchCtx *)de; |
153 | | |
154 | 1.68k | SigMatchAppendSMToList(s, sm, mqtt_qos_id); |
155 | | |
156 | 1.68k | return 0; |
157 | | |
158 | 173 | error: |
159 | 173 | if (de != NULL) |
160 | 0 | SCFree(de); |
161 | 173 | if (sm != NULL) |
162 | 0 | SCFree(sm); |
163 | 173 | return -1; |
164 | 1.68k | } |
165 | | |
166 | | /** |
167 | | * \internal |
168 | | * \brief this function will free memory associated with DetectMQTTQosData |
169 | | * |
170 | | * \param de pointer to DetectMQTTQosData |
171 | | */ |
172 | | void DetectMQTTQosFree(DetectEngineCtx *de_ctx, void *de_ptr) |
173 | 1.68k | { |
174 | 1.68k | if (de_ptr != NULL) |
175 | 1.68k | SCFree(de_ptr); |
176 | 1.68k | } |
177 | | |
178 | | /* |
179 | | * ONLY TESTS BELOW THIS COMMENT |
180 | | */ |
181 | | |
182 | | #ifdef UNITTESTS |
183 | | /** |
184 | | * \test MQTTQosTestParse01 is a test for a valid value |
185 | | * |
186 | | * \retval 1 on success |
187 | | * \retval 0 on failure |
188 | | */ |
189 | | static int MQTTQosTestParse01 (void) |
190 | | { |
191 | | uint8_t *de = NULL; |
192 | | |
193 | | de = DetectMQTTQosParse("0"); |
194 | | FAIL_IF_NULL(de); |
195 | | FAIL_IF_NOT(*de == 0); |
196 | | DetectMQTTQosFree(NULL, de); |
197 | | |
198 | | de = DetectMQTTQosParse(" 0"); |
199 | | FAIL_IF_NULL(de); |
200 | | FAIL_IF_NOT(*de == 0); |
201 | | DetectMQTTQosFree(NULL, de); |
202 | | |
203 | | de = DetectMQTTQosParse("1"); |
204 | | FAIL_IF_NULL(de); |
205 | | FAIL_IF_NOT(*de == 1); |
206 | | DetectMQTTQosFree(NULL, de); |
207 | | |
208 | | de = DetectMQTTQosParse("2"); |
209 | | FAIL_IF_NULL(de); |
210 | | FAIL_IF_NOT(*de == 2); |
211 | | DetectMQTTQosFree(NULL, de); |
212 | | |
213 | | PASS; |
214 | | } |
215 | | |
216 | | /** |
217 | | * \test MQTTQosTestParse02 is a test for an invalid value |
218 | | * |
219 | | * \retval 1 on success |
220 | | * \retval 0 on failure |
221 | | */ |
222 | | static int MQTTQosTestParse02 (void) |
223 | | { |
224 | | uint8_t *de = NULL; |
225 | | de = DetectMQTTQosParse("3"); |
226 | | if (de) { |
227 | | DetectMQTTQosFree(NULL, de); |
228 | | FAIL; |
229 | | } |
230 | | |
231 | | PASS; |
232 | | } |
233 | | |
234 | | /** |
235 | | * \test MQTTQosTestParse04 is a test for an invalid value |
236 | | * |
237 | | * \retval 1 on success |
238 | | * \retval 0 on failure |
239 | | */ |
240 | | static int MQTTQosTestParse03 (void) |
241 | | { |
242 | | uint8_t *de = NULL; |
243 | | de = DetectMQTTQosParse("12"); |
244 | | if (de) { |
245 | | DetectMQTTQosFree(NULL, de); |
246 | | FAIL; |
247 | | } |
248 | | |
249 | | PASS; |
250 | | } |
251 | | |
252 | | |
253 | | #endif /* UNITTESTS */ |
254 | | |
255 | | /** |
256 | | * \brief this function registers unit tests for MQTTQos |
257 | | */ |
258 | | void MQTTQosRegisterTests(void) |
259 | 0 | { |
260 | | #ifdef UNITTESTS |
261 | | UtRegisterTest("MQTTQosTestParse01", MQTTQosTestParse01); |
262 | | UtRegisterTest("MQTTQosTestParse02", MQTTQosTestParse02); |
263 | | UtRegisterTest("MQTTQosTestParse03", MQTTQosTestParse03); |
264 | | #endif /* UNITTESTS */ |
265 | 0 | } |