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