]> git.ipfire.org Git - people/ms/suricata.git/blame - src/detect-engine-uint.c
pcre: use pcre2 to parse detect pcre itself
[people/ms/suricata.git] / src / detect-engine-uint.c
CommitLineData
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 36static DetectParseRegex uint_pcre;
75ec5283
PA
37
38
39int 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
88DetectU32Data *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
220void
221PrefilterPacketU32Set(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
229bool
230PrefilterPacketU32Compare(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 240static bool g_detect_uint_registered = false;
75ec5283 241
a5572890 242void 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
252int 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
300DetectU8Data *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}