1 /* Copyright (C) 2020 Open Information Security Foundation
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
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.
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
21 * \author Philippe Antoine <p.antoine@catenacyber.fr>
25 #include "suricata-common.h"
27 #include "util-byte.h"
28 #include "detect-parse.h"
29 #include "detect-engine-uint.h"
32 * \brief Regex for parsing our options
34 #define PARSE_REGEX "^\\s*([0-9]*)?\\s*([<>=-]+)?\\s*([0-9]+)?\\s*$"
36 static DetectParseRegex uint_pcre
;
39 int DetectU32Match(const uint32_t parg
, const DetectU32Data
*du32
)
43 if (parg
== du32
->arg1
) {
48 if (parg
< du32
->arg1
) {
53 if (parg
<= du32
->arg1
) {
58 if (parg
> du32
->arg1
) {
63 if (parg
>= du32
->arg1
) {
68 if (parg
> du32
->arg1
&& parg
< du32
->arg2
) {
73 BUG_ON("unknown mode");
78 static int DetectU32Validate(DetectU32Data
*du32
)
82 if (du32
->arg1
== 0) {
87 if (du32
->arg1
== UINT32_MAX
) {
92 if (du32
->arg1
>= du32
->arg2
) {
95 // we need at least one value that can match parg > du32->arg1 && parg < du32->arg2
96 if (du32
->arg1
+ 1 >= du32
->arg2
) {
107 * \brief This function is used to parse u32 options passed via some u32 keyword
109 * \param u32str Pointer to the user provided u32 options
111 * \retval DetectU32Data pointer to DetectU32Data on success
112 * \retval NULL on failure
115 DetectU32Data
*DetectU32Parse (const char *u32str
)
117 /* We initialize these to please static checkers, these values will
118 either be updated or not used later on */
119 DetectU32Data u32da
= {0, 0, 0};
120 DetectU32Data
*u32d
= NULL
;
125 int ret
= 0, res
= 0;
128 ret
= DetectParsePcreExec(&uint_pcre
, u32str
, 0, 0);
129 if (ret
< 2 || ret
> 4) {
130 SCLogError(SC_ERR_PCRE_MATCH
, "parse error, ret %" PRId32
"", ret
);
134 pcre2len
= sizeof(arg1
);
135 res
= pcre2_substring_copy_bynumber(uint_pcre
.match
, 1, (PCRE2_UCHAR8
*)arg1
, &pcre2len
);
137 SCLogError(SC_ERR_PCRE_COPY_SUBSTRING
, "pcre2_substring_copy_bynumber failed");
140 SCLogDebug("Arg1 \"%s\"", arg1
);
143 pcre2len
= sizeof(arg2
);
144 res
= pcre2_substring_copy_bynumber(uint_pcre
.match
, 2, (PCRE2_UCHAR8
*)arg2
, &pcre2len
);
146 SCLogError(SC_ERR_PCRE_COPY_SUBSTRING
, "pcre2_substring_copy_bynumber failed");
149 SCLogDebug("Arg2 \"%s\"", arg2
);
152 pcre2len
= sizeof(arg3
);
153 res
= pcre2_substring_copy_bynumber(
154 uint_pcre
.match
, 3, (PCRE2_UCHAR8
*)arg3
, &pcre2len
);
156 SCLogError(SC_ERR_PCRE_COPY_SUBSTRING
, "pcre2_substring_copy_bynumber failed");
159 SCLogDebug("Arg3 \"%s\"", arg3
);
163 if (strlen(arg2
) > 0) {
168 if (strlen(arg2
) == 1) {
169 if (strlen(arg3
) == 0)
172 if (ByteExtractStringUint32(&u32da
.arg1
, 10, strlen(arg3
), arg3
) < 0) {
173 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED
, "ByteExtractStringUint32 failed");
177 SCLogDebug("u32 is %" PRIu32
"", u32da
.arg1
);
178 if (strlen(arg1
) > 0)
181 if (arg2
[0] == '<') {
182 u32da
.mode
= DETECT_UINT_LT
;
183 } else { // arg2[0] == '>'
184 u32da
.mode
= DETECT_UINT_GT
;
187 } else if (strlen(arg2
) == 2) {
188 if (arg2
[0] == '<' && arg2
[1] == '=') {
189 u32da
.mode
= DETECT_UINT_LTE
;
191 } else if (arg2
[0] == '>' || arg2
[1] == '=') {
192 u32da
.mode
= DETECT_UINT_GTE
;
194 } else if (arg2
[0] != '<' || arg2
[1] != '>') {
202 if (strlen(arg1
)== 0)
204 if (strlen(arg3
)== 0)
207 u32da
.mode
= DETECT_UINT_RA
;
208 if (ByteExtractStringUint32(&u32da
.arg1
, 10, strlen(arg1
), arg1
) < 0) {
209 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED
, "ByteExtractStringUint32 failed");
212 if (ByteExtractStringUint32(&u32da
.arg2
, 10, strlen(arg3
), arg3
) < 0) {
213 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED
, "ByteExtractStringUint32 failed");
217 SCLogDebug("u32 is %"PRIu32
" to %"PRIu32
"", u32da
.arg1
, u32da
.arg2
);
218 if (u32da
.arg1
>= u32da
.arg2
) {
219 SCLogError(SC_ERR_INVALID_SIGNATURE
, "Invalid u32 range. ");
224 u32da
.mode
= DETECT_UINT_EQ
;
226 if (strlen(arg2
) > 0 ||
231 if (ByteExtractStringUint32(&u32da
.arg1
, 10, strlen(arg1
), arg1
) < 0) {
232 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED
, "ByteExtractStringUint32 failed");
237 u32da
.mode
= DETECT_UINT_EQ
;
239 if (strlen(arg3
) > 0 ||
243 if (ByteExtractStringUint32(&u32da
.arg1
, 10, strlen(arg1
), arg1
) < 0) {
244 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED
, "ByteExtractStringUint32 failed");
248 if (DetectU32Validate(&u32da
)) {
249 SCLogError(SC_ERR_INVALID_VALUE
, "Impossible value for uint32 condition : %s", u32str
);
252 u32d
= SCCalloc(1, sizeof (DetectU32Data
));
253 if (unlikely(u32d
== NULL
))
255 u32d
->arg1
= u32da
.arg1
;
256 u32d
->arg2
= u32da
.arg2
;
257 u32d
->mode
= u32da
.mode
;
263 PrefilterPacketU32Set(PrefilterPacketHeaderValue
*v
, void *smctx
)
265 const DetectU32Data
*a
= smctx
;
272 PrefilterPacketU32Compare(PrefilterPacketHeaderValue v
, void *smctx
)
274 const DetectU32Data
*a
= smctx
;
275 if (v
.u8
[0] == a
->mode
&&
276 v
.u32
[1] == a
->arg1
&&
282 static bool g_detect_uint_registered
= false;
284 void DetectUintRegister(void)
286 if (g_detect_uint_registered
== false) {
287 // register only once
288 DetectSetupParseRegexes(PARSE_REGEX
, &uint_pcre
);
289 g_detect_uint_registered
= true;
293 //same as u32 but with u8
294 int DetectU8Match(const uint8_t parg
, const DetectU8Data
*du8
)
298 if (parg
== du8
->arg1
) {
303 if (parg
< du8
->arg1
) {
307 case DETECT_UINT_LTE
:
308 if (parg
<= du8
->arg1
) {
313 if (parg
> du8
->arg1
) {
317 case DETECT_UINT_GTE
:
318 if (parg
>= du8
->arg1
) {
323 if (parg
> du8
->arg1
&& parg
< du8
->arg2
) {
328 BUG_ON("unknown mode");
333 static int DetectU8Validate(DetectU8Data
*du8
)
337 if (du8
->arg1
== 0) {
342 if (du8
->arg1
== UINT8_MAX
) {
347 if (du8
->arg1
>= du8
->arg2
) {
350 // we need at least one value that can match parg > du8->arg1 && parg < du8->arg2
351 if (du8
->arg1
+ 1 >= du8
->arg2
) {
362 * \brief This function is used to parse u8 options passed via some u8 keyword
364 * \param u8str Pointer to the user provided u8 options
366 * \retval DetectU8Data pointer to DetectU8Data on success
367 * \retval NULL on failure
370 DetectU8Data
*DetectU8Parse (const char *u8str
)
372 /* We initialize these to please static checkers, these values will
373 either be updated or not used later on */
374 DetectU8Data u8da
= {0, 0, 0};
375 DetectU8Data
*u8d
= NULL
;
380 int ret
= 0, res
= 0;
383 ret
= DetectParsePcreExec(&uint_pcre
, u8str
, 0, 0);
384 if (ret
< 2 || ret
> 4) {
385 SCLogError(SC_ERR_PCRE_MATCH
, "parse error, ret %" PRId32
"", ret
);
389 pcre2len
= sizeof(arg1
);
390 res
= pcre2_substring_copy_bynumber(uint_pcre
.match
, 1, (PCRE2_UCHAR8
*)arg1
, &pcre2len
);
392 SCLogError(SC_ERR_PCRE_COPY_SUBSTRING
, "pcre2_substring_copy_bynumber failed");
395 SCLogDebug("Arg1 \"%s\"", arg1
);
398 pcre2len
= sizeof(arg2
);
399 res
= pcre2_substring_copy_bynumber(uint_pcre
.match
, 2, (PCRE2_UCHAR8
*)arg2
, &pcre2len
);
401 SCLogError(SC_ERR_PCRE_COPY_SUBSTRING
, "pcre2_substring_copy_bynumber failed");
404 SCLogDebug("Arg2 \"%s\"", arg2
);
407 pcre2len
= sizeof(arg3
);
408 res
= pcre2_substring_copy_bynumber(
409 uint_pcre
.match
, 3, (PCRE2_UCHAR8
*)arg3
, &pcre2len
);
411 SCLogError(SC_ERR_PCRE_COPY_SUBSTRING
, "pcre2_substring_copy_bynumber failed");
414 SCLogDebug("Arg3 \"%s\"", arg3
);
418 if (strlen(arg2
) > 0) {
423 if (strlen(arg2
) == 1) {
424 if (StringParseUint8(&u8da
.arg1
, 10, strlen(arg3
), arg3
) < 0) {
425 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED
, "ByteExtractStringUint8 failed");
429 SCLogDebug("u8 is %" PRIu8
"", u8da
.arg1
);
430 if (strlen(arg1
) > 0)
433 if (arg2
[0] == '<') {
434 u8da
.mode
= DETECT_UINT_LT
;
435 } else { // arg2[0] == '>'
436 u8da
.mode
= DETECT_UINT_GT
;
439 } else if (strlen(arg2
) == 2) {
440 if (arg2
[0] == '<' && arg2
[1] == '=') {
441 u8da
.mode
= DETECT_UINT_LTE
;
443 } else if (arg2
[0] == '>' || arg2
[1] == '=') {
444 u8da
.mode
= DETECT_UINT_GTE
;
446 } else if (arg2
[0] != '<' || arg2
[1] != '>') {
454 u8da
.mode
= DETECT_UINT_RA
;
455 if (StringParseUint8(&u8da
.arg1
, 10, strlen(arg1
), arg1
) < 0) {
456 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED
, "ByteExtractStringUint8 failed");
459 if (StringParseUint8(&u8da
.arg2
, 10, strlen(arg3
), arg3
) < 0) {
460 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED
, "ByteExtractStringUint8 failed");
464 SCLogDebug("u8 is %"PRIu8
" to %"PRIu8
"", u8da
.arg1
, u8da
.arg2
);
465 if (u8da
.arg1
>= u8da
.arg2
) {
466 SCLogError(SC_ERR_INVALID_SIGNATURE
, "Invalid u8 range. ");
471 u8da
.mode
= DETECT_UINT_EQ
;
473 if (strlen(arg2
) > 0 ||
477 if (StringParseUint8(&u8da
.arg1
, 10, strlen(arg1
), arg1
) < 0) {
478 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED
, "ByteExtractStringUint8 failed");
483 u8da
.mode
= DETECT_UINT_EQ
;
485 if (strlen(arg3
) > 0)
488 if (StringParseUint8(&u8da
.arg1
, 10, strlen(arg1
), arg1
) < 0) {
489 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED
, "ByteExtractStringUint8 failed");
493 if (DetectU8Validate(&u8da
)) {
494 SCLogError(SC_ERR_INVALID_VALUE
, "Impossible value for uint8 condition : %s", u8str
);
497 u8d
= SCCalloc(1, sizeof (DetectU8Data
));
498 if (unlikely(u8d
== NULL
))
500 u8d
->arg1
= u8da
.arg1
;
501 u8d
->arg2
= u8da
.arg2
;
502 u8d
->mode
= u8da
.mode
;