]>
Commit | Line | Data |
---|---|---|
75ec5283 PA |
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 Philippe Antoine <p.antoine@catenacyber.fr> | |
22 | * | |
23 | */ | |
24 | ||
25 | #include "suricata-common.h" | |
26 | ||
27 | #include "util-byte.h" | |
28 | #include "detect-parse.h" | |
29 | #include "detect-engine-uint.h" | |
30 | ||
31 | /** | |
32 | * \brief Regex for parsing our options | |
33 | */ | |
34 | #define PARSE_REGEX "^\\s*([0-9]*)?\\s*([<>=-]+)?\\s*([0-9]+)?\\s*$" | |
35 | ||
4b0085b0 | 36 | static DetectParseRegex uint_pcre; |
75ec5283 PA |
37 | |
38 | ||
39 | int DetectU32Match(const uint32_t parg, const DetectU32Data *du32) | |
40 | { | |
41 | switch (du32->mode) { | |
42 | case DETECT_UINT_EQ: | |
43 | if (parg == du32->arg1) { | |
44 | return 1; | |
45 | } | |
46 | return 0; | |
47 | case DETECT_UINT_LT: | |
48 | if (parg < du32->arg1) { | |
49 | return 1; | |
50 | } | |
51 | return 0; | |
b80cdae1 | 52 | case DETECT_UINT_LTE: |
53 | if (parg <= du32->arg1) { | |
54 | return 1; | |
55 | } | |
56 | return 0; | |
75ec5283 PA |
57 | case DETECT_UINT_GT: |
58 | if (parg > du32->arg1) { | |
59 | return 1; | |
60 | } | |
61 | return 0; | |
b80cdae1 | 62 | case DETECT_UINT_GTE: |
63 | if (parg >= du32->arg1) { | |
64 | return 1; | |
65 | } | |
66 | return 0; | |
75ec5283 PA |
67 | case DETECT_UINT_RA: |
68 | if (parg > du32->arg1 && parg < du32->arg2) { | |
69 | return 1; | |
70 | } | |
71 | return 0; | |
72 | default: | |
73 | BUG_ON("unknown mode"); | |
74 | } | |
75 | return 0; | |
76 | } | |
77 | ||
78 | ||
79 | /** | |
80 | * \brief This function is used to parse u32 options passed via some u32 keyword | |
81 | * | |
82 | * \param u32str Pointer to the user provided u32 options | |
83 | * | |
84 | * \retval DetectU32Data pointer to DetectU32Data on success | |
85 | * \retval NULL on failure | |
86 | */ | |
87 | ||
88 | DetectU32Data *DetectU32Parse (const char *u32str) | |
89 | { | |
5dc21b0e SS |
90 | /* We initialize these to please static checkers, these values will |
91 | either be updated or not used later on */ | |
92 | DetectU32Data u32da = {0, 0, 0}; | |
75ec5283 PA |
93 | DetectU32Data *u32d = NULL; |
94 | char arg1[16] = ""; | |
95 | char arg2[16] = ""; | |
96 | char arg3[16] = ""; | |
97 | ||
75ec5283 PA |
98 | int ret = 0, res = 0; |
99 | int ov[MAX_SUBSTRINGS]; | |
100 | ||
4b0085b0 | 101 | ret = DetectParsePcreExec(&uint_pcre, u32str, 0, 0, ov, MAX_SUBSTRINGS); |
75ec5283 PA |
102 | if (ret < 2 || ret > 4) { |
103 | SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 "", ret); | |
104 | return NULL; | |
105 | } | |
106 | ||
107 | res = pcre_copy_substring((char *) u32str, ov, MAX_SUBSTRINGS, 1, arg1, sizeof(arg1)); | |
108 | if (res < 0) { | |
109 | SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed"); | |
110 | return NULL; | |
111 | } | |
112 | SCLogDebug("Arg1 \"%s\"", arg1); | |
113 | ||
114 | if (ret >= 3) { | |
115 | res = pcre_copy_substring((char *) u32str, ov, MAX_SUBSTRINGS, 2, arg2, sizeof(arg2)); | |
116 | if (res < 0) { | |
117 | SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed"); | |
118 | return NULL; | |
119 | } | |
120 | SCLogDebug("Arg2 \"%s\"", arg2); | |
121 | ||
122 | if (ret >= 4) { | |
123 | res = pcre_copy_substring((char *) u32str, ov, MAX_SUBSTRINGS, 3, arg3, sizeof(arg3)); | |
124 | if (res < 0) { | |
125 | SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed"); | |
126 | return NULL; | |
127 | } | |
128 | SCLogDebug("Arg3 \"%s\"", arg3); | |
129 | } | |
130 | } | |
131 | ||
132 | if (strlen(arg2) > 0) { | |
133 | /*set the values*/ | |
134 | switch(arg2[0]) { | |
135 | case '<': | |
136 | case '>': | |
137 | if (strlen(arg3) == 0) | |
138 | return NULL; | |
139 | ||
140 | if (ByteExtractStringUint32(&u32da.arg1, 10, strlen(arg3), arg3) < 0) { | |
141 | SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint32 failed"); | |
142 | return NULL; | |
143 | } | |
144 | ||
145 | SCLogDebug("u32 is %"PRIu32"",u32da.arg1); | |
146 | if (strlen(arg1) > 0) | |
147 | return NULL; | |
148 | ||
149 | if (arg2[0] == '<') { | |
b80cdae1 | 150 | if (arg2[1] == '=') { |
151 | u32da.mode = DETECT_UINT_LTE; | |
152 | } else { | |
153 | u32da.mode = DETECT_UINT_LT; | |
154 | } | |
75ec5283 | 155 | } else { // arg2[0] == '>' |
b80cdae1 | 156 | if (arg2[1] == '=') { |
157 | u32da.mode = DETECT_UINT_GTE; | |
158 | } else { | |
159 | u32da.mode = DETECT_UINT_GT; | |
160 | } | |
75ec5283 PA |
161 | } |
162 | break; | |
163 | case '-': | |
164 | if (strlen(arg1)== 0) | |
165 | return NULL; | |
166 | if (strlen(arg3)== 0) | |
167 | return NULL; | |
168 | ||
169 | u32da.mode = DETECT_UINT_RA; | |
170 | if (ByteExtractStringUint32(&u32da.arg1, 10, strlen(arg1), arg1) < 0) { | |
171 | SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint32 failed"); | |
172 | return NULL; | |
173 | } | |
174 | if (ByteExtractStringUint32(&u32da.arg2, 10, strlen(arg3), arg3) < 0) { | |
175 | SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint32 failed"); | |
176 | return NULL; | |
177 | } | |
178 | ||
179 | SCLogDebug("u32 is %"PRIu32" to %"PRIu32"", u32da.arg1, u32da.arg2); | |
180 | if (u32da.arg1 >= u32da.arg2) { | |
181 | SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid u32 range. "); | |
182 | return NULL; | |
183 | } | |
184 | break; | |
185 | default: | |
186 | u32da.mode = DETECT_UINT_EQ; | |
187 | ||
188 | if (strlen(arg2) > 0 || | |
189 | strlen(arg3) > 0 || | |
190 | strlen(arg1) == 0) | |
191 | return NULL; | |
192 | ||
193 | if (ByteExtractStringUint32(&u32da.arg1, 10, strlen(arg1), arg1) < 0) { | |
194 | SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint32 failed"); | |
195 | return NULL; | |
196 | } | |
197 | } | |
198 | } else { | |
199 | u32da.mode = DETECT_UINT_EQ; | |
200 | ||
201 | if (strlen(arg3) > 0 || | |
202 | strlen(arg1) == 0) | |
203 | return NULL; | |
204 | ||
205 | if (ByteExtractStringUint32(&u32da.arg1, 10, strlen(arg1), arg1) < 0) { | |
206 | SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint32 failed"); | |
207 | return NULL; | |
208 | } | |
209 | } | |
210 | u32d = SCCalloc(1, sizeof (DetectU32Data)); | |
211 | if (unlikely(u32d == NULL)) | |
212 | return NULL; | |
213 | u32d->arg1 = u32da.arg1; | |
214 | u32d->arg2 = u32da.arg2; | |
215 | u32d->mode = u32da.mode; | |
216 | ||
217 | return u32d; | |
218 | } | |
219 | ||
220 | void | |
221 | PrefilterPacketU32Set(PrefilterPacketHeaderValue *v, void *smctx) | |
222 | { | |
223 | const DetectU32Data *a = smctx; | |
224 | v->u8[0] = a->mode; | |
225 | v->u32[1] = a->arg1; | |
226 | v->u32[2] = a->arg2; | |
227 | } | |
228 | ||
229 | bool | |
230 | PrefilterPacketU32Compare(PrefilterPacketHeaderValue v, void *smctx) | |
231 | { | |
232 | const DetectU32Data *a = smctx; | |
233 | if (v.u8[0] == a->mode && | |
234 | v.u32[1] == a->arg1 && | |
235 | v.u32[2] == a->arg2) | |
236 | return true; | |
237 | return false; | |
238 | } | |
239 | ||
a5572890 | 240 | static bool g_detect_uint_registered = false; |
75ec5283 | 241 | |
a5572890 | 242 | void DetectUintRegister(void) |
75ec5283 | 243 | { |
a5572890 | 244 | if (g_detect_uint_registered == false) { |
75ec5283 | 245 | // register only once |
4b0085b0 | 246 | DetectSetupParseRegexes(PARSE_REGEX, &uint_pcre); |
a5572890 | 247 | g_detect_uint_registered = true; |
75ec5283 PA |
248 | } |
249 | } | |
a5572890 PA |
250 | |
251 | //same as u32 but with u8 | |
252 | int DetectU8Match(const uint8_t parg, const DetectU8Data *du8) | |
253 | { | |
254 | switch (du8->mode) { | |
255 | case DETECT_UINT_EQ: | |
256 | if (parg == du8->arg1) { | |
257 | return 1; | |
258 | } | |
259 | return 0; | |
260 | case DETECT_UINT_LT: | |
261 | if (parg < du8->arg1) { | |
262 | return 1; | |
263 | } | |
264 | return 0; | |
b80cdae1 | 265 | case DETECT_UINT_LTE: |
266 | if (parg <= du8->arg1) { | |
267 | return 1; | |
268 | } | |
269 | return 0; | |
a5572890 PA |
270 | case DETECT_UINT_GT: |
271 | if (parg > du8->arg1) { | |
272 | return 1; | |
273 | } | |
274 | return 0; | |
b80cdae1 | 275 | case DETECT_UINT_GTE: |
276 | if (parg >= du8->arg1) { | |
277 | return 1; | |
278 | } | |
279 | return 0; | |
a5572890 PA |
280 | case DETECT_UINT_RA: |
281 | if (parg > du8->arg1 && parg < du8->arg2) { | |
282 | return 1; | |
283 | } | |
284 | return 0; | |
285 | default: | |
286 | BUG_ON("unknown mode"); | |
287 | } | |
288 | return 0; | |
289 | } | |
290 | ||
291 | /** | |
292 | * \brief This function is used to parse u8 options passed via some u8 keyword | |
293 | * | |
294 | * \param u8str Pointer to the user provided u8 options | |
295 | * | |
296 | * \retval DetectU8Data pointer to DetectU8Data on success | |
297 | * \retval NULL on failure | |
298 | */ | |
299 | ||
300 | DetectU8Data *DetectU8Parse (const char *u8str) | |
301 | { | |
5dc21b0e SS |
302 | /* We initialize these to please static checkers, these values will |
303 | either be updated or not used later on */ | |
304 | DetectU8Data u8da = {0, 0, 0}; | |
a5572890 PA |
305 | DetectU8Data *u8d = NULL; |
306 | char arg1[16] = ""; | |
307 | char arg2[16] = ""; | |
308 | char arg3[16] = ""; | |
309 | ||
310 | int ret = 0, res = 0; | |
311 | int ov[MAX_SUBSTRINGS]; | |
312 | ||
313 | ret = DetectParsePcreExec(&uint_pcre, u8str, 0, 0, ov, MAX_SUBSTRINGS); | |
314 | if (ret < 2 || ret > 4) { | |
315 | SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 "", ret); | |
316 | return NULL; | |
317 | } | |
318 | ||
319 | res = pcre_copy_substring((char *) u8str, ov, MAX_SUBSTRINGS, 1, arg1, sizeof(arg1)); | |
320 | if (res < 0) { | |
321 | SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed"); | |
322 | return NULL; | |
323 | } | |
324 | SCLogDebug("Arg1 \"%s\"", arg1); | |
325 | ||
326 | if (ret >= 3) { | |
327 | res = pcre_copy_substring((char *) u8str, ov, MAX_SUBSTRINGS, 2, arg2, sizeof(arg2)); | |
328 | if (res < 0) { | |
329 | SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed"); | |
330 | return NULL; | |
331 | } | |
332 | SCLogDebug("Arg2 \"%s\"", arg2); | |
333 | ||
334 | if (ret >= 4) { | |
335 | res = pcre_copy_substring((char *) u8str, ov, MAX_SUBSTRINGS, 3, arg3, sizeof(arg3)); | |
336 | if (res < 0) { | |
337 | SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre_copy_substring failed"); | |
338 | return NULL; | |
339 | } | |
340 | SCLogDebug("Arg3 \"%s\"", arg3); | |
341 | } | |
342 | } | |
343 | ||
344 | if (strlen(arg2) > 0) { | |
345 | /*set the values*/ | |
346 | switch(arg2[0]) { | |
347 | case '<': | |
348 | case '>': | |
349 | if (StringParseUint8(&u8da.arg1, 10, strlen(arg3), arg3) < 0) { | |
350 | SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint8 failed"); | |
351 | return NULL; | |
352 | } | |
353 | ||
354 | SCLogDebug("u8 is %"PRIu8"",u8da.arg1); | |
355 | if (strlen(arg1) > 0) | |
356 | return NULL; | |
357 | ||
358 | if (arg2[0] == '<') { | |
b80cdae1 | 359 | if (arg2[1] == '=') { |
360 | u8da.mode = DETECT_UINT_LTE; | |
361 | } else { | |
362 | u8da.mode = DETECT_UINT_LT; | |
363 | } | |
a5572890 | 364 | } else { // arg2[0] == '>' |
b80cdae1 | 365 | if (arg2[1] == '=') { |
366 | u8da.mode = DETECT_UINT_GTE; | |
367 | } else { | |
368 | u8da.mode = DETECT_UINT_GT; | |
369 | } | |
a5572890 PA |
370 | } |
371 | break; | |
372 | case '-': | |
373 | u8da.mode = DETECT_UINT_RA; | |
374 | if (StringParseUint8(&u8da.arg1, 10, strlen(arg1), arg1) < 0) { | |
375 | SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint8 failed"); | |
376 | return NULL; | |
377 | } | |
378 | if (StringParseUint8(&u8da.arg2, 10, strlen(arg3), arg3) < 0) { | |
379 | SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint8 failed"); | |
380 | return NULL; | |
381 | } | |
382 | ||
383 | SCLogDebug("u8 is %"PRIu8" to %"PRIu8"", u8da.arg1, u8da.arg2); | |
384 | if (u8da.arg1 >= u8da.arg2) { | |
385 | SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid u8 range. "); | |
386 | return NULL; | |
387 | } | |
388 | break; | |
389 | default: | |
390 | u8da.mode = DETECT_UINT_EQ; | |
391 | ||
392 | if (strlen(arg2) > 0 || | |
393 | strlen(arg3) > 0) | |
394 | return NULL; | |
395 | ||
396 | if (StringParseUint8(&u8da.arg1, 10, strlen(arg1), arg1) < 0) { | |
397 | SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint8 failed"); | |
398 | return NULL; | |
399 | } | |
400 | } | |
401 | } else { | |
402 | u8da.mode = DETECT_UINT_EQ; | |
403 | ||
404 | if (strlen(arg3) > 0) | |
405 | return NULL; | |
406 | ||
407 | if (StringParseUint8(&u8da.arg1, 10, strlen(arg1), arg1) < 0) { | |
408 | SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint8 failed"); | |
409 | return NULL; | |
410 | } | |
411 | } | |
412 | u8d = SCCalloc(1, sizeof (DetectU8Data)); | |
413 | if (unlikely(u8d == NULL)) | |
414 | return NULL; | |
415 | u8d->arg1 = u8da.arg1; | |
416 | u8d->arg2 = u8da.arg2; | |
417 | u8d->mode = u8da.mode; | |
418 | ||
419 | return u8d; | |
420 | } |