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(arg3
) == 0)
171 if (ByteExtractStringUint32(&u32da
.arg1
, 10, strlen(arg3
), arg3
) < 0) {
172 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED
, "ByteExtractStringUint32 failed");
176 SCLogDebug("u32 is %"PRIu32
"",u32da
.arg1
);
177 if (strlen(arg1
) > 0)
180 if (arg2
[0] == '<') {
181 if (arg2
[1] == '=') {
182 u32da
.mode
= DETECT_UINT_LTE
;
184 u32da
.mode
= DETECT_UINT_LT
;
186 } else { // arg2[0] == '>'
187 if (arg2
[1] == '=') {
188 u32da
.mode
= DETECT_UINT_GTE
;
190 u32da
.mode
= DETECT_UINT_GT
;
195 if (strlen(arg1
)== 0)
197 if (strlen(arg3
)== 0)
200 u32da
.mode
= DETECT_UINT_RA
;
201 if (ByteExtractStringUint32(&u32da
.arg1
, 10, strlen(arg1
), arg1
) < 0) {
202 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED
, "ByteExtractStringUint32 failed");
205 if (ByteExtractStringUint32(&u32da
.arg2
, 10, strlen(arg3
), arg3
) < 0) {
206 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED
, "ByteExtractStringUint32 failed");
210 SCLogDebug("u32 is %"PRIu32
" to %"PRIu32
"", u32da
.arg1
, u32da
.arg2
);
211 if (u32da
.arg1
>= u32da
.arg2
) {
212 SCLogError(SC_ERR_INVALID_SIGNATURE
, "Invalid u32 range. ");
217 u32da
.mode
= DETECT_UINT_EQ
;
219 if (strlen(arg2
) > 0 ||
224 if (ByteExtractStringUint32(&u32da
.arg1
, 10, strlen(arg1
), arg1
) < 0) {
225 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED
, "ByteExtractStringUint32 failed");
230 u32da
.mode
= DETECT_UINT_EQ
;
232 if (strlen(arg3
) > 0 ||
236 if (ByteExtractStringUint32(&u32da
.arg1
, 10, strlen(arg1
), arg1
) < 0) {
237 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED
, "ByteExtractStringUint32 failed");
241 if (DetectU32Validate(&u32da
)) {
242 SCLogError(SC_ERR_INVALID_VALUE
, "Impossible value for uint32 condition : %s", u32str
);
245 u32d
= SCCalloc(1, sizeof (DetectU32Data
));
246 if (unlikely(u32d
== NULL
))
248 u32d
->arg1
= u32da
.arg1
;
249 u32d
->arg2
= u32da
.arg2
;
250 u32d
->mode
= u32da
.mode
;
256 PrefilterPacketU32Set(PrefilterPacketHeaderValue
*v
, void *smctx
)
258 const DetectU32Data
*a
= smctx
;
265 PrefilterPacketU32Compare(PrefilterPacketHeaderValue v
, void *smctx
)
267 const DetectU32Data
*a
= smctx
;
268 if (v
.u8
[0] == a
->mode
&&
269 v
.u32
[1] == a
->arg1
&&
275 static bool g_detect_uint_registered
= false;
277 void DetectUintRegister(void)
279 if (g_detect_uint_registered
== false) {
280 // register only once
281 DetectSetupParseRegexes(PARSE_REGEX
, &uint_pcre
);
282 g_detect_uint_registered
= true;
286 //same as u32 but with u8
287 int DetectU8Match(const uint8_t parg
, const DetectU8Data
*du8
)
291 if (parg
== du8
->arg1
) {
296 if (parg
< du8
->arg1
) {
300 case DETECT_UINT_LTE
:
301 if (parg
<= du8
->arg1
) {
306 if (parg
> du8
->arg1
) {
310 case DETECT_UINT_GTE
:
311 if (parg
>= du8
->arg1
) {
316 if (parg
> du8
->arg1
&& parg
< du8
->arg2
) {
321 BUG_ON("unknown mode");
326 static int DetectU8Validate(DetectU8Data
*du8
)
330 if (du8
->arg1
== 0) {
335 if (du8
->arg1
== UINT8_MAX
) {
340 if (du8
->arg1
>= du8
->arg2
) {
343 // we need at least one value that can match parg > du8->arg1 && parg < du8->arg2
344 if (du8
->arg1
+ 1 >= du8
->arg2
) {
355 * \brief This function is used to parse u8 options passed via some u8 keyword
357 * \param u8str Pointer to the user provided u8 options
359 * \retval DetectU8Data pointer to DetectU8Data on success
360 * \retval NULL on failure
363 DetectU8Data
*DetectU8Parse (const char *u8str
)
365 /* We initialize these to please static checkers, these values will
366 either be updated or not used later on */
367 DetectU8Data u8da
= {0, 0, 0};
368 DetectU8Data
*u8d
= NULL
;
373 int ret
= 0, res
= 0;
376 ret
= DetectParsePcreExec(&uint_pcre
, u8str
, 0, 0);
377 if (ret
< 2 || ret
> 4) {
378 SCLogError(SC_ERR_PCRE_MATCH
, "parse error, ret %" PRId32
"", ret
);
382 pcre2len
= sizeof(arg1
);
383 res
= pcre2_substring_copy_bynumber(uint_pcre
.match
, 1, (PCRE2_UCHAR8
*)arg1
, &pcre2len
);
385 SCLogError(SC_ERR_PCRE_COPY_SUBSTRING
, "pcre2_substring_copy_bynumber failed");
388 SCLogDebug("Arg1 \"%s\"", arg1
);
391 pcre2len
= sizeof(arg2
);
392 res
= pcre2_substring_copy_bynumber(uint_pcre
.match
, 2, (PCRE2_UCHAR8
*)arg2
, &pcre2len
);
394 SCLogError(SC_ERR_PCRE_COPY_SUBSTRING
, "pcre2_substring_copy_bynumber failed");
397 SCLogDebug("Arg2 \"%s\"", arg2
);
400 pcre2len
= sizeof(arg3
);
401 res
= pcre2_substring_copy_bynumber(
402 uint_pcre
.match
, 3, (PCRE2_UCHAR8
*)arg3
, &pcre2len
);
404 SCLogError(SC_ERR_PCRE_COPY_SUBSTRING
, "pcre2_substring_copy_bynumber failed");
407 SCLogDebug("Arg3 \"%s\"", arg3
);
411 if (strlen(arg2
) > 0) {
416 if (StringParseUint8(&u8da
.arg1
, 10, strlen(arg3
), arg3
) < 0) {
417 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED
, "ByteExtractStringUint8 failed");
421 SCLogDebug("u8 is %"PRIu8
"",u8da
.arg1
);
422 if (strlen(arg1
) > 0)
425 if (arg2
[0] == '<') {
426 if (arg2
[1] == '=') {
427 u8da
.mode
= DETECT_UINT_LTE
;
429 u8da
.mode
= DETECT_UINT_LT
;
431 } else { // arg2[0] == '>'
432 if (arg2
[1] == '=') {
433 u8da
.mode
= DETECT_UINT_GTE
;
435 u8da
.mode
= DETECT_UINT_GT
;
440 u8da
.mode
= DETECT_UINT_RA
;
441 if (StringParseUint8(&u8da
.arg1
, 10, strlen(arg1
), arg1
) < 0) {
442 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED
, "ByteExtractStringUint8 failed");
445 if (StringParseUint8(&u8da
.arg2
, 10, strlen(arg3
), arg3
) < 0) {
446 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED
, "ByteExtractStringUint8 failed");
450 SCLogDebug("u8 is %"PRIu8
" to %"PRIu8
"", u8da
.arg1
, u8da
.arg2
);
451 if (u8da
.arg1
>= u8da
.arg2
) {
452 SCLogError(SC_ERR_INVALID_SIGNATURE
, "Invalid u8 range. ");
457 u8da
.mode
= DETECT_UINT_EQ
;
459 if (strlen(arg2
) > 0 ||
463 if (StringParseUint8(&u8da
.arg1
, 10, strlen(arg1
), arg1
) < 0) {
464 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED
, "ByteExtractStringUint8 failed");
469 u8da
.mode
= DETECT_UINT_EQ
;
471 if (strlen(arg3
) > 0)
474 if (StringParseUint8(&u8da
.arg1
, 10, strlen(arg1
), arg1
) < 0) {
475 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED
, "ByteExtractStringUint8 failed");
479 if (DetectU8Validate(&u8da
)) {
480 SCLogError(SC_ERR_INVALID_VALUE
, "Impossible value for uint8 condition : %s", u8str
);
483 u8d
= SCCalloc(1, sizeof (DetectU8Data
));
484 if (unlikely(u8d
== NULL
))
486 u8d
->arg1
= u8da
.arg1
;
487 u8d
->arg2
= u8da
.arg2
;
488 u8d
->mode
= u8da
.mode
;