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