suricata
detect-parse.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2025 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 Victor Julien <victor@inliniac.net>
22 *
23 * signature parser
24 */
25
26#include "suricata-common.h"
27
28#include "detect.h"
29#include "detect-engine.h"
31#include "detect-engine-port.h"
32#include "detect-engine-mpm.h"
33#include "detect-engine-state.h"
34#include "detect-engine-build.h"
35
36#include "detect-content.h"
37#include "detect-bsize.h"
38#include "detect-isdataat.h"
39#include "detect-pcre.h"
40#include "detect-uricontent.h"
41#include "detect-reference.h"
42#include "detect-ipproto.h"
43#include "detect-flow.h"
45#include "detect-lua.h"
47#include "detect-http-method.h"
48
49#include "pkt-var.h"
50#include "host.h"
51#include "util-profiling.h"
52#include "decode.h"
53
54#include "flow.h"
55
56#include "util-rule-vars.h"
57#include "conf.h"
58#include "conf-yaml-loader.h"
59
60#include "app-layer.h"
61#include "app-layer-protos.h"
62#include "app-layer-parser.h"
63#include "app-layer-htp.h"
64
66#include "util-unittest.h"
68#include "util-debug.h"
69#include "string.h"
70#include "detect-parse.h"
72#include "detect-engine-file.h"
74
75#include "action-globals.h"
76#include "util-validate.h"
77
78/* Table with all SigMatch registrations */
80
81extern bool sc_set_caps;
82
83static void SigMatchTransferSigMatchAcrossLists(SigMatch *sm,
84 SigMatch **src_sm_list, SigMatch **src_sm_list_tail,
85 SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail);
86
87/**
88 * \brief Registration table for file handlers
89 */
90/**
91 * \brief We use this as data to the hash table DetectEngineCtx->dup_sig_hash_table.
92 */
93typedef struct SigDuplWrapper_ {
94 /* the signature we want to wrap */
96 /* the signature right before the above signature in the det_ctx->sig_list */
99
100/** helper structure for sig parsing */
111
112const char *DetectListToHumanString(int list)
113{
114#define CASE_CODE_STRING(E, S) case E: return S; break
115 switch (list) {
123 CASE_CODE_STRING(DETECT_SM_LIST_MAX, "max (internal)");
124 }
125#undef CASE_CODE_STRING
126 return "unknown";
127}
128
129#define CASE_CODE(E) case E: return #E
144
145/** \param arg NULL or empty string */
147 Signature *s, const char *arg, int sm_type, int sm_list,
148 AppProto alproto)
149{
150 SigMatch *sm = NULL;
151 int ret = -1;
152
153 if (arg != NULL && strcmp(arg, "") != 0) {
154 SCLogError("%s shouldn't be supplied "
155 "with an argument",
156 sigmatch_table[sm_type].name);
157 goto end;
158 }
159
161 SCLogError("\"%s\" keyword seen "
162 "with a sticky buffer still set. Reset sticky buffer "
163 "with pkt_data before using the modifier.",
164 sigmatch_table[sm_type].name);
165 goto end;
166 }
167 if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(s->alproto, alproto)) {
168 SCLogError("rule contains conflicting "
169 "alprotos set");
170 goto end;
171 }
172
175 if (sm == NULL) {
176 SCLogError("\"%s\" keyword "
177 "found inside the rule without a content context. "
178 "Please use a \"content\" keyword before using the "
179 "\"%s\" keyword",
180 sigmatch_table[sm_type].name, sigmatch_table[sm_type].name);
181 goto end;
182 }
184 if (cd->flags & DETECT_CONTENT_RAWBYTES) {
185 SCLogError("%s rule can not "
186 "be used with the rawbytes rule keyword",
187 sigmatch_table[sm_type].name);
188 goto end;
189 }
190 if (cd->flags & DETECT_CONTENT_REPLACE) {
191 SCLogError("%s rule can not "
192 "be used with the replace rule keyword",
193 sigmatch_table[sm_type].name);
194 goto end;
195 }
199 if (pm != NULL) {
200 if (pm->type == DETECT_CONTENT) {
201 DetectContentData *tmp_cd = (DetectContentData *)pm->ctx;
202 tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT;
203 } else {
204 DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx;
205 tmp_pd->flags &= ~DETECT_PCRE_RELATIVE_NEXT;
206 }
207 }
208
209 if (s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id == sm_list) {
212 if (pm != NULL) {
213 if (pm->type == DETECT_CONTENT) {
214 DetectContentData *tmp_cd = (DetectContentData *)pm->ctx;
216 } else {
217 DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx;
219 }
220 }
221 }
222 }
223 s->alproto = alproto;
225
226 if (s->init_data->curbuf == NULL || (int)s->init_data->curbuf->id != sm_list) {
227 if (s->init_data->curbuf != NULL && s->init_data->curbuf->head == NULL) {
228 SCLogError("no matches for previous buffer");
229 return -1;
230 }
231 bool reuse_buffer = false;
232 if (s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id != sm_list) {
233 for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
234 if (s->init_data->buffers[x].id == (uint32_t)sm_list) {
235 s->init_data->curbuf = &s->init_data->buffers[x];
236 reuse_buffer = true;
237 break;
238 }
239 }
240 }
241
242 if (!reuse_buffer) {
244 SCLogError("failed to expand rule buffer array");
245 return -1;
246 }
247
248 /* initialize a new buffer */
250 s->init_data->curbuf->id = sm_list;
251 s->init_data->curbuf->head = NULL;
252 s->init_data->curbuf->tail = NULL;
253 SCLogDebug("idx %u list %d set up curbuf %p s->init_data->buffer_index %u",
254 s->init_data->buffer_index - 1, sm_list, s->init_data->curbuf,
256 }
257 }
258
259 /* transfer the sm from the pmatch list to sm_list */
260 SigMatchTransferSigMatchAcrossLists(sm, &s->init_data->smlists[DETECT_SM_LIST_PMATCH],
262 &s->init_data->curbuf->tail);
263
264 if (sm->type == DETECT_CONTENT) {
266 MAX(s->init_data->max_content_list_id, (uint32_t)sm_list);
267 }
268
269 ret = 0;
270 end:
271 return ret;
272}
273
275{
276 SigMatch *sm = SCCalloc(1, sizeof(SigMatch));
277 if (unlikely(sm == NULL))
278 return NULL;
279
280 sm->prev = NULL;
281 sm->next = NULL;
282 return sm;
283}
284
285/** \brief free a SigMatch
286 * \param sm SigMatch to free.
287 */
289{
290 if (sm == NULL)
291 return;
292
293 /** free the ctx, for that we call the Free func */
294 if (sm->ctx != NULL) {
295 if (sigmatch_table[sm->type].Free != NULL) {
296 sigmatch_table[sm->type].Free(de_ctx, sm->ctx);
297 }
298 }
299 SCFree(sm);
300}
301
302static enum DetectKeywordId SigTableGetIndex(const SigTableElmt *e)
303{
304 const SigTableElmt *table = &sigmatch_table[0];
305 ptrdiff_t offset = e - table;
307 return (enum DetectKeywordId)offset;
308}
309
310/* Get the detection module by name */
311static SigTableElmt *SigTableGet(char *name)
312{
313 SigTableElmt *st = NULL;
314 int i = 0;
315
316 for (i = 0; i < DETECT_TBLSIZE; i++) {
317 st = &sigmatch_table[i];
318
319 if (st->name != NULL) {
320 if (strcasecmp(name,st->name) == 0)
321 return st;
322 if (st->alias != NULL && strcasecmp(name,st->alias) == 0)
323 return st;
324 }
325 }
326
327 return NULL;
328}
329
335
337{
338 if ((int)id < DETECT_TBLSIZE) {
339 return ((sigmatch_table[id].flags & SIGMATCH_STRICT_PARSING) != 0);
340 }
341 return false;
342}
343
345{
346 if (str == NULL) {
347 /* nothing to be done */
348 return;
349 }
350
351 /* "all" just sets the flag for each keyword */
352 if (strcmp(str, "all") == 0) {
353 for (int i = 0; i < DETECT_TBLSIZE; i++) {
356 }
357 return;
358 }
359
360 char *copy = SCStrdup(str);
361 if (copy == NULL)
362 FatalError("could not duplicate opt string");
363
364 char *xsaveptr = NULL;
365 char *key = strtok_r(copy, ",", &xsaveptr);
366 while (key != NULL) {
367 SigTableElmt *st = SigTableGet(key);
368 if (st != NULL) {
370 } else {
371 SCLogWarning("'strict' command line "
372 "argument '%s' not found",
373 key);
374 }
375 key = strtok_r(NULL, ",", &xsaveptr);
376 }
377
378 SCFree(copy);
379}
380
381/**
382 * \brief Append a SigMatch to the list type.
383 *
384 * \param s Signature.
385 * \param new The sig match to append.
386 * \param list The list to append to.
387 */
389 DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
390{
391 SigMatch *new = SigMatchAlloc();
392 if (new == NULL)
393 return NULL;
394
395 new->type = type;
396 new->ctx = ctx;
397
398 if (new->type == DETECT_CONTENT) {
400 }
401
402 SCLogDebug("s:%p new:%p list:%d: %s, s->init_data->list_set %s s->init_data->list %d", s, new,
403 list, sigmatch_table[new->type].name, BOOL2STR(s->init_data->list_set),
404 s->init_data->list);
405
406 if (list < DETECT_SM_LIST_MAX) {
407 if (s->init_data->smlists[list] == NULL) {
408 s->init_data->smlists[list] = new;
409 s->init_data->smlists_tail[list] = new;
410 new->next = NULL;
411 new->prev = NULL;
412 } else {
413 SigMatch *cur = s->init_data->smlists_tail[list];
414 cur->next = new;
415 new->prev = cur;
416 new->next = NULL;
417 s->init_data->smlists_tail[list] = new;
418 }
419 new->idx = s->init_data->sm_cnt;
420 s->init_data->sm_cnt++;
421
422 } else {
423 /* app-layer-events (and possibly others?) can get here w/o a "list"
424 * already set up. */
425
426 /* unset any existing list if it isn't the same as the new */
427 if (s->init_data->list != DETECT_SM_LIST_NOTSET && list != s->init_data->list) {
428 SCLogDebug("reset: list %d != s->init_data->list %d", list, s->init_data->list);
430 }
431
432 if (s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id != list) {
433 for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
434 if (s->init_data->buffers[x].id == (uint32_t)list &&
436 SCLogDebug("reusing buffer %u as it isn't multi-capable", x);
437 s->init_data->curbuf = &s->init_data->buffers[x];
438 break;
439 }
440 }
441 }
442
443 if ((s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id != list) ||
444 s->init_data->curbuf == NULL) {
446 SCLogError("failed to expand rule buffer array");
447 new->ctx = NULL;
448 SigMatchFree(de_ctx, new);
449 return NULL;
450 } else {
451 /* initialize new buffer */
453 s->init_data->curbuf->id = list;
454 /* buffer set up by sigmatch is tracked in case we add a stickybuffer for the
455 * same list. */
456 s->init_data->curbuf->sm_init = true;
458 s->init_data->curbuf->only_tc = true;
459 }
461 s->init_data->curbuf->only_ts = true;
462 }
463 SCLogDebug("s->init_data->buffer_index %u", s->init_data->buffer_index);
464 }
465 }
466 BUG_ON(s->init_data->curbuf == NULL);
467
468 new->prev = s->init_data->curbuf->tail;
469 if (s->init_data->curbuf->tail)
470 s->init_data->curbuf->tail->next = new;
471 if (s->init_data->curbuf->head == NULL)
472 s->init_data->curbuf->head = new;
473 s->init_data->curbuf->tail = new;
474 new->idx = s->init_data->sm_cnt;
475 s->init_data->sm_cnt++;
476 SCLogDebug("appended %s to list %d, rule pos %u (s->init_data->list %d)",
477 sigmatch_table[new->type].name, list, new->idx, s->init_data->list);
478
479 for (SigMatch *sm = s->init_data->curbuf->head; sm != NULL; sm = sm->next) {
480 SCLogDebug("buf:%p: id:%u: '%s' pos %u", s->init_data->curbuf, s->init_data->curbuf->id,
481 sigmatch_table[sm->type].name, sm->idx);
482 }
483 }
484 return new;
485}
486
488{
489 if (sm == s->init_data->smlists[sm_list]) {
490 s->init_data->smlists[sm_list] = sm->next;
491 }
492 if (sm == s->init_data->smlists_tail[sm_list]) {
493 s->init_data->smlists_tail[sm_list] = sm->prev;
494 }
495 if (sm->prev != NULL)
496 sm->prev->next = sm->next;
497 if (sm->next != NULL)
498 sm->next->prev = sm->prev;
499}
500
501/**
502 * \brief Returns a pointer to the last SigMatch instance of a particular type
503 * in a Signature of the payload list.
504 *
505 * \param s Pointer to the tail of the sigmatch list
506 * \param type SigMatch type which has to be searched for in the Signature.
507 *
508 * \retval match Pointer to the last SigMatch instance of type 'type'.
509 */
510static SigMatch *SigMatchGetLastSMByType(SigMatch *sm, int type)
511{
512 while (sm != NULL) {
513 if (sm->type == type) {
514 return sm;
515 }
516 sm = sm->prev;
517 }
518
519 return NULL;
520}
521
522/** \brief get the last SigMatch from lists that support
523 * MPM.
524 * \note only supports the lists that are registered through
525 * DetectBufferTypeSupportsMpm().
526 */
528{
529 SigMatch *sm_last = NULL;
530 SigMatch *sm_new;
531 uint32_t sm_type;
532
533 for (uint32_t i = 0; i < s->init_data->buffer_index; i++) {
534 const int id = s->init_data->buffers[i].id;
537 if (sm_new == NULL)
538 continue;
539 if (sm_last == NULL || sm_new->idx > sm_last->idx)
540 sm_last = sm_new;
541 }
542 }
543 /* otherwise brute force it */
544 for (sm_type = 0; sm_type < DETECT_SM_LIST_MAX; sm_type++) {
546 continue;
547 SigMatch *sm_list = s->init_data->smlists_tail[sm_type];
548 sm_new = SigMatchGetLastSMByType(sm_list, DETECT_CONTENT);
549 if (sm_new == NULL)
550 continue;
551 if (sm_last == NULL || sm_new->idx > sm_last->idx)
552 sm_last = sm_new;
553 }
554
555 return sm_last;
556}
557
558/**
559 * \brief Returns the sm with the largest index (added latest) from the lists
560 * passed to us.
561 *
562 * \retval Pointer to Last sm.
563 */
565{
566 SigMatch *sm_last = NULL;
567 SigMatch *sm_new;
568
569 SCLogDebug("s->init_data->buffer_index %u", s->init_data->buffer_index);
570 for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
572 s->init_data->list != (int)s->init_data->buffers[x].id) {
573 SCLogDebug("skip x %u s->init_data->list %d (int)s->init_data->buffers[x].id %d", x,
574 s->init_data->list, (int)s->init_data->buffers[x].id);
575
576 continue;
577 }
578 int sm_type;
579 va_list ap;
580 va_start(ap, s);
581
582 for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
583 sm_new = SigMatchGetLastSMByType(s->init_data->buffers[x].tail, sm_type);
584 if (sm_new == NULL)
585 continue;
586 if (sm_last == NULL || sm_new->idx > sm_last->idx)
587 sm_last = sm_new;
588 }
589 va_end(ap);
590 }
591
592 for (int buf_type = 0; buf_type < DETECT_SM_LIST_MAX; buf_type++) {
593 if (s->init_data->smlists[buf_type] == NULL)
594 continue;
596 buf_type != s->init_data->list)
597 continue;
598
599 int sm_type;
600 va_list ap;
601 va_start(ap, s);
602
603 for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int))
604 {
605 sm_new = SigMatchGetLastSMByType(s->init_data->smlists_tail[buf_type], sm_type);
606 if (sm_new == NULL)
607 continue;
608 if (sm_last == NULL || sm_new->idx > sm_last->idx)
609 sm_last = sm_new;
610 }
611 va_end(ap);
612 }
613
614 return sm_last;
615}
616
617/**
618 * \brief Returns the sm with the largest index (added last) from the list
619 * passed to us as a pointer.
620 *
621 * \param sm_list pointer to the SigMatch we should look before
622 * \param va_args list of keyword types terminated by -1
623 *
624 * \retval sm_last to last sm.
625 */
627{
628 SigMatch *sm_last = NULL;
629 SigMatch *sm_new;
630 int sm_type;
631
632 va_list ap;
633 va_start(ap, sm_list);
634
635 for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int))
636 {
637 sm_new = SigMatchGetLastSMByType(sm_list, sm_type);
638 if (sm_new == NULL)
639 continue;
640 if (sm_last == NULL || sm_new->idx > sm_last->idx)
641 sm_last = sm_new;
642 }
643
644 va_end(ap);
645
646 return sm_last;
647}
648
649/**
650 * \brief Returns the sm with the largest index (added last) from the list
651 * passed to us as an id.
652 *
653 * \param list_id id of the list to be searched
654 * \param va_args list of keyword types terminated by -1
655 *
656 * \retval sm_last to last sm.
657 */
658SigMatch *DetectGetLastSMByListId(const Signature *s, int list_id, ...)
659{
660 SigMatch *sm_last = NULL;
661 SigMatch *sm_new;
662 int sm_type;
663
664 if ((uint32_t)list_id >= DETECT_SM_LIST_MAX) {
665 for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
666 sm_new = s->init_data->buffers[x].tail;
667 if (sm_new == NULL)
668 continue;
669
670 va_list ap;
671 va_start(ap, list_id);
672
673 for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
674 sm_new = SigMatchGetLastSMByType(s->init_data->buffers[x].tail, sm_type);
675 if (sm_new == NULL)
676 continue;
677 if (sm_last == NULL || sm_new->idx > sm_last->idx)
678 sm_last = sm_new;
679 }
680
681 va_end(ap);
682 }
683 } else {
684 SigMatch *sm_list = s->init_data->smlists_tail[list_id];
685 if (sm_list == NULL)
686 return NULL;
687
688 va_list ap;
689 va_start(ap, list_id);
690
691 for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
692 sm_new = SigMatchGetLastSMByType(sm_list, sm_type);
693 if (sm_new == NULL)
694 continue;
695 if (sm_last == NULL || sm_new->idx > sm_last->idx)
696 sm_last = sm_new;
697 }
698
699 va_end(ap);
700 }
701 return sm_last;
702}
703
704/**
705 * \brief Returns the sm with the largest index (added latest) from this sig
706 *
707 * \retval sm_last Pointer to last sm
708 */
710{
711 SigMatch *sm_last = NULL;
712 SigMatch *sm_new;
713
714 for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
715 sm_new = s->init_data->buffers[x].tail;
716 if (sm_new == NULL)
717 continue;
718 if (sm_last == NULL || sm_new->idx > sm_last->idx)
719 sm_last = sm_new;
720 }
721
722 for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
723 sm_new = s->init_data->smlists_tail[i];
724 if (sm_new == NULL)
725 continue;
726 if (sm_last == NULL || sm_new->idx > sm_last->idx)
727 sm_last = sm_new;
728 }
729
730 return sm_last;
731}
732
733static void SigMatchTransferSigMatchAcrossLists(SigMatch *sm,
734 SigMatch **src_sm_list, SigMatch **src_sm_list_tail,
735 SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail)
736{
737 /* we won't do any checks for args */
738
739 if (sm->prev != NULL)
740 sm->prev->next = sm->next;
741 if (sm->next != NULL)
742 sm->next->prev = sm->prev;
743
744 if (sm == *src_sm_list)
745 *src_sm_list = sm->next;
746 if (sm == *src_sm_list_tail)
747 *src_sm_list_tail = sm->prev;
748
749 if (*dst_sm_list == NULL) {
750 *dst_sm_list = sm;
751 *dst_sm_list_tail = sm;
752 sm->next = NULL;
753 sm->prev = NULL;
754 } else {
755 SigMatch *cur = *dst_sm_list_tail;
756 cur->next = sm;
757 sm->prev = cur;
758 sm->next = NULL;
759 *dst_sm_list_tail = sm;
760 }
761}
762
763int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm)
764{
765 if (key_sm == NULL)
766 return -1;
767
768 for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
769 const SigMatch *sm = s->init_data->buffers[x].head;
770 while (sm != NULL) {
771 if (sm == key_sm)
772 return s->init_data->buffers[x].id;
773 sm = sm->next;
774 }
775 }
776
777 for (int list = 0; list < DETECT_SM_LIST_MAX; list++) {
778 const SigMatch *sm = s->init_data->smlists[list];
779 while (sm != NULL) {
780 if (sm == key_sm)
781 return list;
782 sm = sm->next;
783 }
784 }
785
786 SCLogError("Unable to find the sm in any of the "
787 "sm lists");
788 return -1;
789}
790
791/**
792 * \brief Parse and setup a direction
793 *
794 * \param s signature
795 * \param str argument to the keyword
796 * \param only_dir argument wether the keyword only accepts a direction
797 *
798 * \retval 0 on success, -1 on failure
799 */
800static int DetectSetupDirection(Signature *s, char **str, bool only_dir)
801{
802 char *orig = *str;
803 if (strncmp(*str, "to_client", strlen("to_client")) == 0) {
804 *str += strlen("to_client");
805 // skip space
806 while (**str && isblank(**str)) {
807 (*str)++;
808 }
809 // check comma or nothing
810 if (**str) {
811 if (only_dir) {
812 SCLogError("unknown option: only accepts to_server or to_client");
813 return -1;
814 }
815 if (**str != ',') {
816 // leave to_client_something for next parser if not only_dir
817 *str = orig;
818 return 0;
819 } else {
820 (*str)++;
821 }
822 while (**str && isblank(**str)) {
823 (*str)++;
824 }
825 }
827 if ((s->flags & SIG_FLAG_TXBOTHDIR) == 0) {
828 if (s->flags & SIG_FLAG_TOSERVER) {
829 SCLogError("contradictory directions");
830 return -1;
831 }
833 }
834 } else if (strncmp(*str, "to_server", strlen("to_server")) == 0) {
835 *str += strlen("to_server");
836 // skip space
837 while (**str && isblank(**str)) {
838 (*str)++;
839 }
840 // check comma or nothing
841 if (**str) {
842 if (only_dir) {
843 SCLogError("unknown option: only accepts to_server or to_client");
844 return -1;
845 }
846 if (**str != ',') {
847 // leave to_client_something for next parser if not only_dir
848 *str = orig;
849 return 0;
850 } else {
851 (*str)++;
852 }
853 while (**str && isblank(**str)) {
854 (*str)++;
855 }
856 }
858 if ((s->flags & SIG_FLAG_TXBOTHDIR) == 0) {
859 if (s->flags & SIG_FLAG_TOCLIENT) {
860 SCLogError("contradictory directions");
861 return -1;
862 }
864 }
865 } else if (only_dir) {
866 SCLogError("unknown option: only accepts to_server or to_client");
867 return -1;
868 }
869 return 0;
870}
871
872static int SigParseOptions(DetectEngineCtx *de_ctx, Signature *s, char *optstr, char *output,
873 size_t output_size, bool requires)
874{
875 SigTableElmt *st = NULL;
876 char *optname = NULL;
877 char *optvalue = NULL;
878
879 /* Trim leading space. */
880 while (isblank(*optstr)) {
881 optstr++;
882 }
883
884 /* Look for the end of this option, handling escaped semicolons. */
885 char *optend = optstr;
886 for (;;) {
887 optend = strchr(optend, ';');
888 if (optend == NULL) {
889 SCLogError("no terminating \";\" found");
890 goto error;
891 }
892 else if (optend > optstr && *(optend -1 ) == '\\') {
893 optend++;
894 } else {
895 break;
896 }
897 }
898 *(optend++) = '\0';
899
900 /* Find the start of the option value. */
901 char *optvalptr = strchr(optstr, ':');
902 if (optvalptr) {
903 *(optvalptr++) = '\0';
904
905 /* Trim trailing space from name. */
906 for (size_t i = strlen(optvalptr); i > 0; i--) {
907 if (isblank(optvalptr[i - 1])) {
908 optvalptr[i - 1] = '\0';
909 } else {
910 break;
911 }
912 }
913
914 optvalue = optvalptr;
915 }
916
917 /* Trim trailing space from name. */
918 for (size_t i = strlen(optstr); i > 0; i--) {
919 if (isblank(optstr[i - 1])) {
920 optstr[i - 1] = '\0';
921 } else {
922 break;
923 }
924 }
925 optname = optstr;
926
927 /* Check for options that are only to be processed during the
928 * first "requires" pass. */
929 bool requires_only = strcasecmp(optname, "requires") == 0 || strcasecmp(optname, "sid") == 0;
930 if ((requires && !requires_only) || (!requires && requires_only)) {
931 goto finish;
932 }
933
934 /* Call option parsing */
935 st = SigTableGet(optname);
936 if (st == NULL || st->Setup == NULL) {
937 SCLogError("unknown rule keyword '%s'.", optname);
938 goto error;
939 }
940
942 if (optvalue == NULL || strlen(optvalue) == 0) {
944 "invalid formatting or malformed option to %s keyword: '%s'", optname, optstr);
945 goto error;
946 }
947 } else if (st->flags & SIGMATCH_NOOPT) {
948 if (optvalue && strlen(optvalue)) {
949 SCLogError("unexpected option to %s keyword: '%s'", optname, optstr);
950 goto error;
951 }
952 }
953 s->init_data->negated = false;
954
955 const enum DetectKeywordId idx = SigTableGetIndex(st);
957
959#define URL "https://suricata.io/our-story/deprecation-policy/"
960 if (st->alternative == 0)
961 SCLogWarning("keyword '%s' is deprecated "
962 "and will be removed soon. See %s",
963 st->name, URL);
964 else
965 SCLogWarning("keyword '%s' is deprecated "
966 "and will be removed soon. Use '%s' instead. "
967 "See %s",
969#undef URL
970 }
971
972 int setup_ret = 0;
973
974 /* Validate double quoting, trimming trailing white space along the way. */
975 if (optvalue != NULL && strlen(optvalue) > 0) {
976 size_t ovlen = strlen(optvalue);
977 char *ptr = optvalue;
978
979 /* skip leading whitespace */
980 while (ovlen > 0) {
981 if (!isblank(*ptr))
982 break;
983 ptr++;
984 ovlen--;
985 }
986 if (ovlen == 0) {
987 SCLogError("invalid formatting or malformed option to %s keyword: \'%s\'", optname,
988 optstr);
989 goto error;
990 }
991
992 if (s->init_data->firewall_rule && (st->flags & SIGMATCH_SUPPORT_FIREWALL) == 0) {
993 SCLogWarning("keyword \'%s\' has not been tested for firewall rules", optname);
994 }
995
996 /* see if value is negated */
997 if ((st->flags & SIGMATCH_HANDLE_NEGATION) && *ptr == '!') {
998 s->init_data->negated = true;
999 ptr++;
1000 ovlen--;
1001 }
1002 /* skip more whitespace */
1003 while (ovlen > 0) {
1004 if (!isblank(*ptr))
1005 break;
1006 ptr++;
1007 ovlen--;
1008 }
1009 if (ovlen == 0) {
1010 SCLogError("invalid formatting or malformed option to %s keyword: \'%s\'", optname,
1011 optstr);
1012 goto error;
1013 }
1014 /* if quoting is mandatory, enforce it */
1015 if (st->flags & SIGMATCH_QUOTES_MANDATORY && ovlen && *ptr != '"') {
1016 SCLogError("invalid formatting to %s keyword: "
1017 "value must be double quoted \'%s\'",
1018 optname, optstr);
1019 goto error;
1020 }
1021
1023 && ovlen && *ptr == '"')
1024 {
1025 for (; ovlen > 0; ovlen--) {
1026 if (isblank(ptr[ovlen - 1])) {
1027 ptr[ovlen - 1] = '\0';
1028 } else {
1029 break;
1030 }
1031 }
1032 if (ovlen && ptr[ovlen - 1] != '"') {
1033 SCLogError("bad option value formatting (possible missing semicolon) "
1034 "for keyword %s: \'%s\'",
1035 optname, optvalue);
1036 goto error;
1037 }
1038 if (ovlen > 1) {
1039 /* strip leading " */
1040 ptr++;
1041 ovlen--;
1042 ptr[ovlen - 1] = '\0';
1043 ovlen--;
1044 }
1045 if (ovlen == 0) {
1046 SCLogError("bad input "
1047 "for keyword %s: \'%s\'",
1048 optname, optvalue);
1049 goto error;
1050 }
1051 } else {
1052 if (*ptr == '"') {
1053 SCLogError(
1054 "quotes on %s keyword that doesn't support them: \'%s\'", optname, optstr);
1055 goto error;
1056 }
1057 }
1058 /* setup may or may not add a new SigMatch to the list */
1059 if (st->flags & SIGMATCH_SUPPORT_DIR) {
1060 if (DetectSetupDirection(s, &ptr, st->flags & SIGMATCH_OPTIONAL_OPT) < 0) {
1061 SCLogError("%s failed to setup direction", st->name);
1062 goto error;
1063 }
1064 }
1065 setup_ret = st->Setup(de_ctx, s, ptr);
1066 s->init_data->init_flags &= ~SIG_FLAG_INIT_FORCE_TOSERVER;
1067 s->init_data->init_flags &= ~SIG_FLAG_INIT_FORCE_TOCLIENT;
1068 } else {
1069 /* setup may or may not add a new SigMatch to the list */
1070 setup_ret = st->Setup(de_ctx, s, NULL);
1071 }
1072 if (setup_ret < 0) {
1073 SCLogDebug("\"%s\" failed to setup", st->name);
1074
1075 /* handle 'silent' error case */
1076 if (setup_ret == -2) {
1077 if (!de_ctx->sm_types_silent_error[idx]) {
1078 de_ctx->sm_types_silent_error[idx] = true;
1079 return -1;
1080 }
1081 return -2;
1082 }
1083 return setup_ret;
1084 }
1085 s->init_data->negated = false;
1086
1087finish:
1088 if (strlen(optend) > 0) {
1089 strlcpy(output, optend, output_size);
1090 return 1;
1091 }
1092
1093 return 0;
1094
1095error:
1096 return -1;
1097}
1098
1099/** \brief Parse address string and update signature
1100 *
1101 * \retval 0 ok, -1 error
1102 */
1103static int SigParseAddress(DetectEngineCtx *de_ctx,
1104 Signature *s, const char *addrstr, char flag)
1105{
1106 SCLogDebug("Address Group \"%s\" to be parsed now", addrstr);
1107
1108 /* pass on to the address(list) parser */
1109 if (flag == 0) {
1110 if (strcasecmp(addrstr, "any") == 0)
1111 s->flags |= SIG_FLAG_SRC_ANY;
1112
1113 s->init_data->src = DetectParseAddress(de_ctx, addrstr,
1115 if (s->init_data->src == NULL)
1116 goto error;
1117 } else {
1118 if (strcasecmp(addrstr, "any") == 0)
1119 s->flags |= SIG_FLAG_DST_ANY;
1120
1121 s->init_data->dst = DetectParseAddress(de_ctx, addrstr,
1123 if (s->init_data->dst == NULL)
1124 goto error;
1125 }
1126
1127 return 0;
1128
1129error:
1130 return -1;
1131}
1132
1133static bool IsBuiltIn(const char *n)
1134{
1135 if (strcmp(n, "request_started") == 0 || strcmp(n, "response_started") == 0) {
1136 return true;
1137 }
1138 if (strcmp(n, "request_complete") == 0 || strcmp(n, "response_complete") == 0) {
1139 return true;
1140 }
1141 return false;
1142}
1143
1144/** \brief register app hooks as generic lists
1145 *
1146 * Register each hook in each app protocol as:
1147 * <alproto>:<hook name>:generic
1148 * These lists can be used by lua scripts to hook into.
1149 *
1150 * \todo move elsewhere? maybe a detect-engine-hook.c?
1151 */
1153{
1154 for (AppProto a = ALPROTO_FAILED + 1; a < g_alproto_max; a++) {
1155 const char *alproto_name = AppProtoToString(a);
1156 if (strcmp(alproto_name, "http") == 0)
1157 alproto_name = "http1";
1158 SCLogDebug("alproto %u/%s", a, alproto_name);
1159
1160 const int max_progress_ts =
1162 const int max_progress_tc =
1164
1165 char ts_tx_started[64];
1166 snprintf(ts_tx_started, sizeof(ts_tx_started), "%s:request_started:generic", alproto_name);
1168 ts_tx_started, a, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL);
1169 SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "request_name", ts_tx_started,
1170 (uint32_t)strlen(ts_tx_started));
1171
1172 char tc_tx_started[64];
1173 snprintf(tc_tx_started, sizeof(tc_tx_started), "%s:response_started:generic", alproto_name);
1175 tc_tx_started, a, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL);
1176 SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "response_name", tc_tx_started,
1177 (uint32_t)strlen(tc_tx_started));
1178
1179 char ts_tx_complete[64];
1180 snprintf(ts_tx_complete, sizeof(ts_tx_complete), "%s:request_complete:generic",
1181 alproto_name);
1182 DetectAppLayerInspectEngineRegister(ts_tx_complete, a, SIG_FLAG_TOSERVER, max_progress_ts,
1184 SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "request_name", ts_tx_complete,
1185 (uint32_t)strlen(ts_tx_complete));
1186
1187 char tc_tx_complete[64];
1188 snprintf(tc_tx_complete, sizeof(tc_tx_complete), "%s:response_complete:generic",
1189 alproto_name);
1190 DetectAppLayerInspectEngineRegister(tc_tx_complete, a, SIG_FLAG_TOCLIENT, max_progress_tc,
1192 SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "response_name", tc_tx_complete,
1193 (uint32_t)strlen(tc_tx_complete));
1194
1195 for (int p = 0; p <= max_progress_ts; p++) {
1197 IPPROTO_TCP /* TODO no ipproto */, a, p, STREAM_TOSERVER);
1198 if (name != NULL && !IsBuiltIn(name)) {
1199 char list_name[64];
1200 snprintf(list_name, sizeof(list_name), "%s:%s:generic", alproto_name, name);
1201 SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, name, list_name,
1202 (uint32_t)strlen(list_name));
1203
1205 list_name, a, SIG_FLAG_TOSERVER, p, DetectEngineInspectGenericList, NULL);
1206 }
1207 }
1208 for (int p = 0; p <= max_progress_tc; p++) {
1210 IPPROTO_TCP /* TODO no ipproto */, a, p, STREAM_TOCLIENT);
1211 if (name != NULL && !IsBuiltIn(name)) {
1212 char list_name[64];
1213 snprintf(list_name, sizeof(list_name), "%s:%s:generic", alproto_name, name);
1214 SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, name, list_name,
1215 (uint32_t)strlen(list_name));
1216
1218 list_name, a, SIG_FLAG_TOCLIENT, p, DetectEngineInspectGenericList, NULL);
1219 }
1220 }
1221 }
1222}
1223
1224#ifdef DEBUG
1225static const char *SignatureHookTypeToString(enum SignatureHookType t)
1226{
1227 switch (t) {
1229 return "not_set";
1231 return "app";
1233 return "pkt";
1234 }
1235 return "unknown";
1236}
1237#endif
1238
1239static enum SignatureHookPkt HookPktFromString(const char *str)
1240{
1241 if (strcmp(str, "flow_start") == 0) {
1243 } else if (strcmp(str, "pre_flow") == 0) {
1245 } else if (strcmp(str, "pre_stream") == 0) {
1247 } else if (strcmp(str, "all") == 0) {
1249 }
1251}
1252
1253#ifdef DEBUG
1254static const char *HookPktToString(const enum SignatureHookPkt ph)
1255{
1256 switch (ph) {
1258 return "not set";
1260 return "flow_start";
1262 return "pre_flow";
1264 return "pre_stream";
1266 return "all";
1267 }
1268 return "error";
1269}
1270#endif
1271
1272static SignatureHook SetPktHook(const char *hook_str)
1273{
1274 SignatureHook h = {
1276 .t.pkt.ph = HookPktFromString(hook_str),
1277 };
1278 return h;
1279}
1280
1281/**
1282 * \param proto_hook string of protocol and hook, e.g. dns:request_complete
1283 */
1284static int SigParseProtoHookPkt(Signature *s, const char *proto_hook, const char *p, const char *h)
1285{
1286 enum SignatureHookPkt hook = HookPktFromString(h);
1287 if (hook != SIGNATURE_HOOK_PKT_NOT_SET) {
1288 s->init_data->hook = SetPktHook(h);
1290 return -1; // TODO unreachable?
1291 }
1292 } else {
1293 SCLogError("unknown pkt hook %s", h);
1294 return -1;
1295 }
1296
1297 SCLogDebug("protocol:%s hook:%s: type:%s parsed hook:%s", p, h,
1298 SignatureHookTypeToString(s->init_data->hook.type),
1299 HookPktToString(s->init_data->hook.t.pkt.ph));
1300 return 0;
1301}
1302
1303static SignatureHook SetAppHook(const AppProto alproto, int progress)
1304{
1305 SignatureHook h = {
1307 .t.app.alproto = alproto,
1308 .t.app.app_progress = progress,
1309 };
1310 return h;
1311}
1312
1313/**
1314 * \param proto_hook string of protocol and hook, e.g. dns:request_complete
1315 */
1316static int SigParseProtoHookApp(Signature *s, const char *proto_hook, const char *p, const char *h)
1317{
1318 if (strcmp(h, "request_started") == 0) {
1320 s->init_data->hook =
1321 SetAppHook(s->alproto, 0); // state 0 should be the starting state in each protocol.
1322 } else if (strcmp(h, "response_started") == 0) {
1324 s->init_data->hook =
1325 SetAppHook(s->alproto, 0); // state 0 should be the starting state in each protocol.
1326 } else if (strcmp(h, "request_complete") == 0) {
1328 s->init_data->hook = SetAppHook(s->alproto,
1330 } else if (strcmp(h, "response_complete") == 0) {
1332 s->init_data->hook = SetAppHook(s->alproto,
1334 } else {
1335 const int progress_ts = AppLayerParserGetStateIdByName(
1336 IPPROTO_TCP /* TODO */, s->alproto, h, STREAM_TOSERVER);
1337 if (progress_ts >= 0) {
1339 s->init_data->hook = SetAppHook(s->alproto, progress_ts);
1340 } else {
1341 const int progress_tc = AppLayerParserGetStateIdByName(
1342 IPPROTO_TCP /* TODO */, s->alproto, h, STREAM_TOCLIENT);
1343 if (progress_tc < 0) {
1344 return -1;
1345 }
1347 s->init_data->hook = SetAppHook(s->alproto, progress_tc);
1348 }
1349 }
1350
1351 char generic_hook_name[64];
1352 snprintf(generic_hook_name, sizeof(generic_hook_name), "%s:generic", proto_hook);
1353 int list = DetectBufferTypeGetByName(generic_hook_name);
1354 if (list < 0) {
1355 SCLogError("no list registered as %s for hook %s", generic_hook_name, proto_hook);
1356 return -1;
1357 }
1358 s->init_data->hook.sm_list = list;
1359
1360 SCLogDebug("protocol:%s hook:%s: type:%s alproto:%u hook:%d", p, h,
1361 SignatureHookTypeToString(s->init_data->hook.type), s->init_data->hook.t.app.alproto,
1363
1365 return 0;
1366}
1367
1368/**
1369 * \brief Parses the protocol supplied by the Signature.
1370 *
1371 * http://www.iana.org/assignments/protocol-numbers
1372 *
1373 * \param s Pointer to the Signature instance to which the parsed
1374 * protocol has to be added.
1375 * \param protostr Pointer to the character string containing the protocol name.
1376 *
1377 * \retval 0 On successfully parsing the protocol sent as the argument.
1378 * \retval -1 On failure
1379 */
1380static int SigParseProto(Signature *s, const char *protostr)
1381{
1382 SCEnter();
1383 if (strlen(protostr) > 32)
1384 return -1;
1385
1386 char proto[33];
1387 strlcpy(proto, protostr, 33);
1388 const char *p = proto;
1389 const char *h = NULL;
1390
1391 bool has_hook = strchr(proto, ':') != NULL;
1392 if (has_hook) {
1393 char *xsaveptr = NULL;
1394 p = strtok_r(proto, ":", &xsaveptr);
1395 h = strtok_r(NULL, ":", &xsaveptr);
1396 SCLogDebug("p: '%s' h: '%s'", p, h);
1397 }
1398 if (p == NULL) {
1399 SCLogError("invalid protocol specification '%s'", proto);
1400 return -1;
1401 }
1402
1403 int r = DetectProtoParse(&s->proto, p);
1404 if (r < 0) {
1406 /* indicate that the signature is app-layer */
1407 if (s->alproto != ALPROTO_UNKNOWN) {
1409
1411
1412 if (h) {
1413 if (SigParseProtoHookApp(s, protostr, p, h) < 0) {
1414 SCLogError("protocol \"%s\" does not support hook \"%s\"", p, h);
1415 SCReturnInt(-1);
1416 }
1417 }
1418 }
1419 else {
1420 SCLogError("protocol \"%s\" cannot be used "
1421 "in a signature. Either detection for this protocol "
1422 "is not yet supported OR detection has been disabled for "
1423 "protocol through the yaml option "
1424 "app-layer.protocols.%s.detection-enabled",
1425 p, p);
1426 SCReturnInt(-1);
1427 }
1428 } else if (h != NULL) {
1429 SCLogDebug("non-app-layer rule with %s:%s", p, h);
1430
1431 if (SigParseProtoHookPkt(s, protostr, p, h) < 0) {
1432 SCLogError("protocol \"%s\" does not support hook \"%s\"", p, h);
1433 SCReturnInt(-1);
1434 }
1435 }
1436
1437 /* if any of these flags are set they are set in a mutually exclusive
1438 * manner */
1441 } else if (s->proto.flags & DETECT_PROTO_ONLY_STREAM) {
1443 }
1444
1445 SCReturnInt(0);
1446}
1447
1448/**
1449 * \brief Parses the port(source or destination) field, from a Signature.
1450 *
1451 * \param s Pointer to the signature which has to be updated with the
1452 * port information.
1453 * \param portstr Pointer to the character string containing the port info.
1454 * \param Flag which indicates if the portstr received is src or dst
1455 * port. For src port: flag = 0, dst port: flag = 1.
1456 *
1457 * \retval 0 On success.
1458 * \retval -1 On failure.
1459 */
1460static int SigParsePort(const DetectEngineCtx *de_ctx,
1461 Signature *s, const char *portstr, char flag)
1462{
1463 int r = 0;
1464
1465 /* XXX VJ exclude handling this for none UDP/TCP proto's */
1466
1467 SCLogDebug("Port group \"%s\" to be parsed", portstr);
1468
1469 if (flag == 0) {
1470 if (strcasecmp(portstr, "any") == 0)
1471 s->flags |= SIG_FLAG_SP_ANY;
1472
1473 r = DetectPortParse(de_ctx, &s->sp, (char *)portstr);
1474 } else if (flag == 1) {
1475 if (strcasecmp(portstr, "any") == 0)
1476 s->flags |= SIG_FLAG_DP_ANY;
1477
1478 r = DetectPortParse(de_ctx, &s->dp, (char *)portstr);
1479 }
1480
1481 if (r < 0)
1482 return -1;
1483
1484 return 0;
1485}
1486
1487/** \retval 1 valid
1488 * \retval 0 invalid
1489 */
1490static int SigParseActionRejectValidate(const char *action)
1491{
1492#ifdef HAVE_LIBNET11
1493#if defined HAVE_LIBCAP_NG && !defined HAVE_LIBNET_CAPABILITIES
1494 if (sc_set_caps) {
1495 SCLogError("Libnet 1.1 is "
1496 "incompatible with POSIX based capabilities with privs dropping. "
1497 "For rejects to work, run as root/super user.");
1498 return 0;
1499 }
1500#endif
1501#else /* no libnet 1.1 */
1502 SCLogError("Libnet 1.1.x is "
1503 "required for action \"%s\" but is not compiled into Suricata",
1504 action);
1505 return 0;
1506#endif
1507 return 1;
1508}
1509
1510/** \retval 0 on error
1511 * \retval flags on success
1512 */
1513static uint8_t ActionStringToFlags(const char *action)
1514{
1515 if (strcasecmp(action, "alert") == 0) {
1516 return ACTION_ALERT;
1517 } else if (strcasecmp(action, "drop") == 0) {
1518 return ACTION_DROP | ACTION_ALERT;
1519 } else if (strcasecmp(action, "pass") == 0) {
1520 return ACTION_PASS;
1521 } else if (strcasecmp(action, "reject") == 0 ||
1522 strcasecmp(action, "rejectsrc") == 0)
1523 {
1524 if (!(SigParseActionRejectValidate(action)))
1525 return 0;
1527 } else if (strcasecmp(action, "rejectdst") == 0) {
1528 if (!(SigParseActionRejectValidate(action)))
1529 return 0;
1531 } else if (strcasecmp(action, "rejectboth") == 0) {
1532 if (!(SigParseActionRejectValidate(action)))
1533 return 0;
1535 } else if (strcasecmp(action, "config") == 0) {
1536 return ACTION_CONFIG;
1537 } else if (strcasecmp(action, "accept") == 0) {
1538 return ACTION_ACCEPT;
1539 } else {
1540 SCLogError("An invalid action \"%s\" was given", action);
1541 return 0;
1542 }
1543}
1544
1545/**
1546 * \brief Parses the action that has been used by the Signature and allots it
1547 * to its Signature instance.
1548 *
1549 * \param s Pointer to the Signature instance to which the action belongs.
1550 * \param action Pointer to the action string used by the Signature.
1551 *
1552 * \retval 0 On successfully parsing the action string and adding it to the
1553 * Signature.
1554 * \retval -1 On failure.
1555 */
1556static int SigParseAction(Signature *s, const char *action_in)
1557{
1558 char action[32];
1559 strlcpy(action, action_in, sizeof(action));
1560 const char *a = action;
1561 const char *o = NULL;
1562
1563 bool has_scope = strchr(action, ':') != NULL;
1564 if (has_scope) {
1565 char *xsaveptr = NULL;
1566 a = strtok_r(action, ":", &xsaveptr);
1567 o = strtok_r(NULL, ":", &xsaveptr);
1568 SCLogDebug("a: '%s' o: '%s'", a, o);
1569 }
1570 if (a == NULL) {
1571 SCLogError("invalid protocol specification '%s'", action_in);
1572 return -1;
1573 }
1574
1575 uint8_t flags = ActionStringToFlags(a);
1576 if (flags == 0)
1577 return -1;
1578
1579 /* parse scope, if any */
1580 if (o) {
1581 uint8_t scope_flags = 0;
1582 if (flags & (ACTION_DROP | ACTION_PASS)) {
1583 if (strcmp(o, "packet") == 0) {
1584 scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
1585 } else if (strcmp(o, "flow") == 0) {
1586 scope_flags = (uint8_t)ACTION_SCOPE_FLOW;
1587 } else {
1588 SCLogError("invalid action scope '%s' in action '%s': only 'packet' and 'flow' "
1589 "allowed",
1590 o, action_in);
1591 return -1;
1592 }
1593 s->action_scope = scope_flags;
1594 } else if (flags & (ACTION_ACCEPT)) {
1595 if (strcmp(o, "packet") == 0) {
1596 scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
1597 } else if (strcmp(o, "hook") == 0) {
1598 scope_flags = (uint8_t)ACTION_SCOPE_HOOK;
1599 } else if (strcmp(o, "tx") == 0) {
1600 scope_flags = (uint8_t)ACTION_SCOPE_TX;
1601 } else if (strcmp(o, "flow") == 0) {
1602 scope_flags = (uint8_t)ACTION_SCOPE_FLOW;
1603 } else {
1604 SCLogError(
1605 "invalid action scope '%s' in action '%s': only 'packet', 'flow', 'tx' and "
1606 "'hook' allowed",
1607 o, action_in);
1608 return -1;
1609 }
1610 s->action_scope = scope_flags;
1611 } else if (flags & (ACTION_CONFIG)) {
1612 if (strcmp(o, "packet") == 0) {
1613 scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
1614 } else {
1615 SCLogError("invalid action scope '%s' in action '%s': only 'packet' allowed", o,
1616 action_in);
1617 return -1;
1618 }
1619 s->action_scope = scope_flags;
1620 } else {
1621 SCLogError("invalid action scope '%s' in action '%s': scope only supported for actions "
1622 "'drop', 'pass' and 'reject'",
1623 o, action_in);
1624 return -1;
1625 }
1626 }
1627
1628 /* require explicit action scope for fw rules */
1629 if (s->init_data->firewall_rule && s->action_scope == 0) {
1630 SCLogError("firewall rules require setting an explicit action scope");
1631 return -1;
1632 }
1633
1634 if (!s->init_data->firewall_rule && (flags & ACTION_ACCEPT)) {
1635 SCLogError("'accept' action only supported for firewall rules");
1636 return -1;
1637 }
1638
1639 if (s->init_data->firewall_rule && (flags & ACTION_PASS)) {
1640 SCLogError("'pass' action not supported for firewall rules");
1641 return -1;
1642 }
1643
1644 s->action = flags;
1645 return 0;
1646}
1647
1648/**
1649 * \brief Parse the next token in rule.
1650 *
1651 * For rule parsing a token is considered to be a string of characters
1652 * separated by white space.
1653 *
1654 * \param input double pointer to input buffer, will be advanced as input is
1655 * parsed.
1656 * \param output buffer to copy token into.
1657 * \param output_size length of output buffer.
1658 */
1659static inline int SigParseToken(char **input, char *output,
1660 const size_t output_size)
1661{
1662 size_t len = *input == NULL ? 0 : strlen(*input);
1663
1664 if (!len) {
1665 return 0;
1666 }
1667
1668 while (len && isblank(**input)) {
1669 (*input)++;
1670 len--;
1671 }
1672
1673 char *endptr = strpbrk(*input, " \t\n\r");
1674 if (endptr != NULL) {
1675 *(endptr++) = '\0';
1676 }
1677 strlcpy(output, *input, output_size);
1678 *input = endptr;
1679
1680 return 1;
1681}
1682
1683/**
1684 * \brief Parse the next rule "list" token.
1685 *
1686 * Parses rule tokens that may be lists such as addresses and ports
1687 * handling the case when they may not be lists.
1688 *
1689 * \param input double pointer to input buffer, will be advanced as input is
1690 * parsed.
1691 * \param output buffer to copy token into.
1692 * \param output_size length of output buffer.
1693 */
1694static inline int SigParseList(char **input, char *output,
1695 const size_t output_size)
1696{
1697 int in_list = 0;
1698 size_t len = *input != NULL ? strlen(*input) : 0;
1699
1700 if (len == 0) {
1701 return 0;
1702 }
1703
1704 while (len && isblank(**input)) {
1705 (*input)++;
1706 len--;
1707 }
1708
1709 size_t i = 0;
1710 for (i = 0; i < len; i++) {
1711 char c = (*input)[i];
1712 if (c == '[') {
1713 in_list++;
1714 } else if (c == ']') {
1715 in_list--;
1716 } else if (c == ' ') {
1717 if (!in_list) {
1718 break;
1719 }
1720 }
1721 }
1722 if (i == len) {
1723 *input = NULL;
1724 return 0;
1725 }
1726 (*input)[i] = '\0';
1727 strlcpy(output, *input, output_size);
1728 *input = *input + i + 1;
1729
1730 return 1;
1731}
1732
1733/**
1734 * \internal
1735 * \brief split a signature string into a few blocks for further parsing
1736 *
1737 * \param scan_only just scan, don't validate
1738 */
1739static int SigParseBasics(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr,
1740 SignatureParser *parser, uint8_t addrs_direction, bool scan_only)
1741{
1742 char *index, dup[DETECT_MAX_RULE_SIZE];
1743
1744 strlcpy(dup, sigstr, DETECT_MAX_RULE_SIZE);
1745 index = dup;
1746
1747 /* Action. */
1748 SigParseToken(&index, parser->action, sizeof(parser->action));
1749
1750 /* Protocol. */
1751 SigParseList(&index, parser->protocol, sizeof(parser->protocol));
1752
1753 /* Source. */
1754 SigParseList(&index, parser->src, sizeof(parser->src));
1755
1756 /* Source port(s). */
1757 SigParseList(&index, parser->sp, sizeof(parser->sp));
1758
1759 /* Direction. */
1760 SigParseToken(&index, parser->direction, sizeof(parser->direction));
1761
1762 /* Destination. */
1763 SigParseList(&index, parser->dst, sizeof(parser->dst));
1764
1765 /* Destination port(s). */
1766 SigParseList(&index, parser->dp, sizeof(parser->dp));
1767
1768 /* Options. */
1769 if (index == NULL) {
1770 SCLogError("no rule options.");
1771 goto error;
1772 }
1773 while (isspace(*index) || *index == '(') {
1774 index++;
1775 }
1776 for (size_t i = strlen(index); i > 0; i--) {
1777 if (isspace(index[i - 1]) || index[i - 1] == ')') {
1778 index[i - 1] = '\0';
1779 } else {
1780 break;
1781 }
1782 }
1783 strlcpy(parser->opts, index, sizeof(parser->opts));
1784
1785 if (scan_only) {
1786 return 0;
1787 }
1788
1789 /* Parse Action */
1790 if (SigParseAction(s, parser->action) < 0)
1791 goto error;
1792
1793 if (SigParseProto(s, parser->protocol) < 0)
1794 goto error;
1795
1796 if (strcmp(parser->direction, "<>") == 0) {
1798 } else if (strcmp(parser->direction, "=>") == 0) {
1799 if (s->flags & SIG_FLAG_FIREWALL) {
1800 SCLogError("transactional bidirectional rules not supported for firewall rules");
1801 goto error;
1802 }
1803
1805 } else if (strcmp(parser->direction, "->") != 0) {
1806 SCLogError("\"%s\" is not a valid direction modifier, "
1807 "\"->\" and \"<>\" are supported.",
1808 parser->direction);
1809 goto error;
1810 }
1811
1812 /* Parse Address & Ports */
1813 if (SigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ addrs_direction) < 0)
1814 goto error;
1815
1816 if (SigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0)
1817 goto error;
1818
1819 /* By AWS - Traditionally we should be doing this only for tcp/udp/sctp,
1820 * but we do it for regardless of ip proto, since the dns/dnstcp/dnsudp
1821 * changes that we made sees to it that at this point of time we don't
1822 * set the ip proto for the sig. We do it a bit later. */
1823 if (SigParsePort(de_ctx, s, parser->sp, SIG_DIREC_SRC ^ addrs_direction) < 0)
1824 goto error;
1825 if (SigParsePort(de_ctx, s, parser->dp, SIG_DIREC_DST ^ addrs_direction) < 0)
1826 goto error;
1827
1828 return 0;
1829
1830error:
1831 return -1;
1832}
1833
1834static inline bool CheckAscii(const char *str)
1835{
1836 for (size_t i = 0; i < strlen(str); i++) {
1837 if (str[i] < 0x20) {
1838 // LF CR TAB
1839 if (str[i] == 0x0a || str[i] == 0x0d || str[i] == 0x09) {
1840 continue;
1841 }
1842 return false;
1843 } else if (str[i] == 0x7f) {
1844 return false;
1845 }
1846 }
1847 return true;
1848}
1849
1850/**
1851 * \brief parse a signature
1852 *
1853 * \param de_ctx detection engine ctx to add it to
1854 * \param s memory structure to store the signature in
1855 * \param sigstr the raw signature as a null terminated string
1856 * \param addrs_direction direction (for bi-directional sigs)
1857 * \param require only scan rule for requires
1858 *
1859 * \param -1 parse error
1860 * \param 0 ok
1861 */
1862static int SigParse(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr,
1863 uint8_t addrs_direction, SignatureParser *parser, bool requires)
1864{
1865 SCEnter();
1866
1867 if (!SCCheckUtf8(sigstr)) {
1868 SCLogError("rule is not valid UTF-8");
1869 SCReturnInt(-1);
1870 }
1871
1872 if (!CheckAscii(sigstr)) {
1873 SCLogError("rule contains invalid (control) characters");
1874 SCReturnInt(-1);
1875 }
1876
1877 int ret = SigParseBasics(de_ctx, s, sigstr, parser, addrs_direction, requires);
1878 if (ret < 0) {
1879 SCLogDebug("SigParseBasics failed");
1880 SCReturnInt(-1);
1881 }
1882
1883 /* we can have no options, so make sure we have them */
1884 if (strlen(parser->opts) > 0) {
1885 size_t buffer_size = strlen(parser->opts) + 1;
1886 char input[buffer_size];
1887 char output[buffer_size];
1888 memset(input, 0x00, buffer_size);
1889 memcpy(input, parser->opts, strlen(parser->opts) + 1);
1890
1891 /* loop the option parsing. Each run processes one option
1892 * and returns the rest of the option string through the
1893 * output variable. */
1894 do {
1895 memset(output, 0x00, buffer_size);
1896 ret = SigParseOptions(de_ctx, s, input, output, buffer_size, requires);
1897 if (ret == 1) {
1898 memcpy(input, output, buffer_size);
1899 }
1900
1901 } while (ret == 1);
1902
1903 if (ret < 0) {
1904 /* Suricata didn't meet the rule requirements, skip. */
1905 goto end;
1906 }
1907 }
1908
1909end:
1911
1912 SCReturnInt(ret);
1913}
1914
1915/** \brief check if buffers array still has space left, expand if not
1916 */
1918{
1919 if (s->init_data->buffers_size >= 64)
1920 return -1;
1921
1922 if (s->init_data->buffer_index + 1 == s->init_data->buffers_size) {
1923 void *ptr = SCRealloc(s->init_data->buffers,
1924 (s->init_data->buffers_size + 8) * sizeof(SignatureInitDataBuffer));
1925 if (ptr == NULL)
1926 return -1;
1927 s->init_data->buffers = ptr;
1928 for (uint32_t x = s->init_data->buffers_size; x < s->init_data->buffers_size + 8; x++) {
1930 memset(b, 0, sizeof(*b));
1931 }
1932 s->init_data->buffers_size += 8;
1933 }
1934 return 0;
1935}
1936
1938{
1939 Signature *sig = SCCalloc(1, sizeof(Signature));
1940 if (unlikely(sig == NULL))
1941 return NULL;
1942
1943 sig->init_data = SCCalloc(1, sizeof(SignatureInitData));
1944 if (sig->init_data == NULL) {
1945 SCFree(sig);
1946 return NULL;
1947 }
1948 sig->init_data->mpm_sm_list = -1;
1949
1951 if (sig->init_data->buffers == NULL) {
1952 SCFree(sig->init_data);
1953 SCFree(sig);
1954 return NULL;
1955 }
1956 sig->init_data->buffers_size = 8;
1957
1958 /* assign it to -1, so that we can later check if the value has been
1959 * overwritten after the Signature has been parsed, and if it hasn't been
1960 * overwritten, we can then assign the default value of 3 */
1961 sig->prio = -1;
1962
1963 /* rule interdepency is false, at start */
1964 sig->init_data->is_rule_state_dependant = false;
1965 /* first index is 0 */
1967
1969 return sig;
1970}
1971
1972/**
1973 * \internal
1974 * \brief Free Metadata list
1975 *
1976 * \param s Pointer to the signature
1977 */
1978static void SigMetadataFree(Signature *s)
1979{
1980 SCEnter();
1981
1982 DetectMetadata *mdata = NULL;
1983 DetectMetadata *next_mdata = NULL;
1984
1985 if (s == NULL || s->metadata == NULL) {
1986 SCReturn;
1987 }
1988
1989 SCLogDebug("s %p, s->metadata %p", s, s->metadata);
1990
1991 for (mdata = s->metadata->list; mdata != NULL;) {
1992 next_mdata = mdata->next;
1993 DetectMetadataFree(mdata);
1994 mdata = next_mdata;
1995 }
1997 SCFree(s->metadata);
1998 s->metadata = NULL;
1999
2000 SCReturn;
2001}
2002
2003/**
2004 * \internal
2005 * \brief Free Reference list
2006 *
2007 * \param s Pointer to the signature
2008 */
2009static void SigRefFree (Signature *s)
2010{
2011 SCEnter();
2012
2013 DetectReference *ref = NULL;
2014 DetectReference *next_ref = NULL;
2015
2016 if (s == NULL) {
2017 SCReturn;
2018 }
2019
2020 SCLogDebug("s %p, s->references %p", s, s->references);
2021
2022 for (ref = s->references; ref != NULL;) {
2023 next_ref = ref->next;
2025 ref = next_ref;
2026 }
2027
2028 s->references = NULL;
2029
2030 SCReturn;
2031}
2032
2033static void SigMatchFreeArrays(DetectEngineCtx *de_ctx, Signature *s, int ctxs)
2034{
2035 if (s != NULL) {
2036 int type;
2037 for (type = 0; type < DETECT_SM_LIST_MAX; type++) {
2038 if (s->sm_arrays[type] != NULL) {
2039 if (ctxs) {
2040 SigMatchData *smd = s->sm_arrays[type];
2041 while(1) {
2042 if (sigmatch_table[smd->type].Free != NULL) {
2043 sigmatch_table[smd->type].Free(de_ctx, smd->ctx);
2044 }
2045 if (smd->is_last)
2046 break;
2047 smd++;
2048 }
2049 }
2050
2051 SCFree(s->sm_arrays[type]);
2052 }
2053 }
2054 }
2055}
2056
2058{
2059 if (s == NULL)
2060 return;
2061
2062 int i;
2063
2064 if (s->init_data && s->init_data->transforms.cnt) {
2065 for(i = 0; i < s->init_data->transforms.cnt; i++) {
2067 int transform = s->init_data->transforms.transforms[i].transform;
2068 sigmatch_table[transform].Free(
2070 s->init_data->transforms.transforms[i].options = NULL;
2071 }
2072 }
2073 }
2074 if (s->init_data) {
2075 for (i = 0; i < DETECT_SM_LIST_MAX; i++) {
2076 SigMatch *sm = s->init_data->smlists[i];
2077 while (sm != NULL) {
2078 SigMatch *nsm = sm->next;
2079 SigMatchFree(de_ctx, sm);
2080 sm = nsm;
2081 }
2082 }
2083
2084 for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2085 SigMatch *sm = s->init_data->buffers[x].head;
2086 while (sm != NULL) {
2087 SigMatch *nsm = sm->next;
2088 SigMatchFree(de_ctx, sm);
2089 sm = nsm;
2090 }
2091 }
2092 if (s->init_data->cidr_dst != NULL)
2094
2095 if (s->init_data->cidr_src != NULL)
2097
2099 s->init_data->buffers = NULL;
2100 }
2101 SigMatchFreeArrays(de_ctx, s, (s->init_data == NULL));
2102 if (s->init_data) {
2103 SCFree(s->init_data);
2104 s->init_data = NULL;
2105 }
2106
2107 if (s->sp != NULL) {
2108 DetectPortCleanupList(NULL, s->sp);
2109 }
2110 if (s->dp != NULL) {
2111 DetectPortCleanupList(NULL, s->dp);
2112 }
2113
2114 if (s->msg != NULL)
2115 SCFree(s->msg);
2116
2117 if (s->addr_src_match4 != NULL) {
2119 }
2120 if (s->addr_dst_match4 != NULL) {
2122 }
2123 if (s->addr_src_match6 != NULL) {
2125 }
2126 if (s->addr_dst_match6 != NULL) {
2128 }
2129 if (s->sig_str != NULL) {
2130 SCFree(s->sig_str);
2131 }
2132
2133 SigRefFree(s);
2134 SigMetadataFree(s);
2135
2137
2138 SCFree(s);
2139}
2140
2141/**
2142 * \brief this function is used to set multiple possible app-layer protos
2143 * \brief into the current signature (for example ja4 for both tls and quic)
2144 *
2145 * \param s pointer to the Current Signature
2146 * \param alprotos an array terminated by ALPROTO_UNKNOWN
2147 *
2148 * \retval 0 on Success
2149 * \retval -1 on Failure
2150 */
2152{
2153 if (s->alproto != ALPROTO_UNKNOWN) {
2154 // One alproto was set, check if it matches the new ones proposed
2155 while (*alprotos != ALPROTO_UNKNOWN) {
2156 if (s->alproto == *alprotos) {
2157 // alproto already set to only one
2158 return 0;
2159 }
2160 alprotos++;
2161 }
2162 // alproto already set and not matching the new set of alprotos
2163 return -1;
2164 }
2165 if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
2166 // check intersection of already used alprotos and new ones
2167 for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2168 if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2169 break;
2170 }
2171 // first disable the ones that do not match
2172 bool found = false;
2173 const AppProto *args = alprotos;
2174 while (*args != ALPROTO_UNKNOWN) {
2175 if (s->init_data->alprotos[i] == *args) {
2176 found = true;
2177 break;
2178 }
2179 args++;
2180 }
2181 if (!found) {
2183 }
2184 }
2185 // Then put at the beginning every defined protocol
2186 for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2187 if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2188 for (AppProto j = SIG_ALPROTO_MAX - 1; j > i; j--) {
2189 if (s->init_data->alprotos[j] != ALPROTO_UNKNOWN) {
2190 s->init_data->alprotos[i] = s->init_data->alprotos[j];
2192 break;
2193 }
2194 }
2195 if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2196 if (i == 0) {
2197 // there was no intersection
2198 return -1;
2199 } else if (i == 1) {
2200 // intersection is singleton, set it as usual
2201 AppProto alproto = s->init_data->alprotos[0];
2203 return SCDetectSignatureSetAppProto(s, alproto);
2204 }
2205 break;
2206 }
2207 }
2208 }
2209 } else {
2210 if (alprotos[0] == ALPROTO_UNKNOWN) {
2211 // do not allow empty set
2212 return -1;
2213 }
2214 if (alprotos[1] == ALPROTO_UNKNOWN) {
2215 // allow singleton, but call traditional setter
2216 return SCDetectSignatureSetAppProto(s, alprotos[0]);
2217 }
2218 // first time we enforce alprotos
2219 for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2220 if (alprotos[i] == ALPROTO_UNKNOWN) {
2221 break;
2222 }
2223 s->init_data->alprotos[i] = alprotos[i];
2224 }
2225 }
2226 return 0;
2227}
2228
2230{
2231 if (!AppProtoIsValid(alproto)) {
2232 SCLogError("invalid alproto %u", alproto);
2233 return -1;
2234 }
2235
2236 if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
2237 // Multiple alprotos were set, check if we restrict to one
2238 bool found = false;
2239 for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2240 if (s->init_data->alprotos[i] == alproto) {
2241 found = true;
2242 break;
2243 }
2244 }
2245 if (!found) {
2246 // fail if we set to a alproto which was not in the set
2247 return -1;
2248 }
2249 // we will use s->alproto if there is a single alproto and
2250 // we reset s->init_data->alprotos to signal there are no longer multiple alprotos
2252 }
2253
2254 if (s->alproto != ALPROTO_UNKNOWN) {
2255 alproto = AppProtoCommon(s->alproto, alproto);
2256 if (alproto == ALPROTO_FAILED) {
2257 SCLogError("can't set rule app proto to %s: already set to %s",
2259 return -1;
2260 }
2261 }
2262
2263 if (AppLayerProtoDetectGetProtoName(alproto) == NULL) {
2264 SCLogError("disabled alproto %s, rule can never match", AppProtoToString(alproto));
2265 return -1;
2266 }
2267 s->alproto = alproto;
2269 return 0;
2270}
2271
2272static DetectMatchAddressIPv4 *SigBuildAddressMatchArrayIPv4(
2273 const DetectAddress *head, uint16_t *match4_cnt)
2274{
2275 uint16_t cnt = 0;
2276
2277 for (const DetectAddress *da = head; da != NULL; da = da->next) {
2278 cnt++;
2279 }
2280 if (cnt == 0) {
2281 return NULL;
2282 }
2283 DetectMatchAddressIPv4 *addr_match4 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv4));
2284 if (addr_match4 == NULL) {
2285 exit(EXIT_FAILURE);
2286 }
2287
2288 uint16_t idx = 0;
2289 for (const DetectAddress *da = head; da != NULL; da = da->next) {
2290 addr_match4[idx].ip = SCNtohl(da->ip.addr_data32[0]);
2291 addr_match4[idx].ip2 = SCNtohl(da->ip2.addr_data32[0]);
2292 idx++;
2293 }
2294 *match4_cnt = cnt;
2295 return addr_match4;
2296}
2297
2298static DetectMatchAddressIPv6 *SigBuildAddressMatchArrayIPv6(
2299 const DetectAddress *head, uint16_t *match6_cnt)
2300{
2301 uint16_t cnt = 0;
2302 for (const DetectAddress *da = head; da != NULL; da = da->next) {
2303 cnt++;
2304 }
2305 if (cnt == 0) {
2306 return NULL;
2307 }
2308
2309 DetectMatchAddressIPv6 *addr_match6 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv6));
2310 if (addr_match6 == NULL) {
2311 exit(EXIT_FAILURE);
2312 }
2313
2314 uint16_t idx = 0;
2315 for (const DetectAddress *da = head; da != NULL; da = da->next) {
2316 addr_match6[idx].ip[0] = SCNtohl(da->ip.addr_data32[0]);
2317 addr_match6[idx].ip[1] = SCNtohl(da->ip.addr_data32[1]);
2318 addr_match6[idx].ip[2] = SCNtohl(da->ip.addr_data32[2]);
2319 addr_match6[idx].ip[3] = SCNtohl(da->ip.addr_data32[3]);
2320 addr_match6[idx].ip2[0] = SCNtohl(da->ip2.addr_data32[0]);
2321 addr_match6[idx].ip2[1] = SCNtohl(da->ip2.addr_data32[1]);
2322 addr_match6[idx].ip2[2] = SCNtohl(da->ip2.addr_data32[2]);
2323 addr_match6[idx].ip2[3] = SCNtohl(da->ip2.addr_data32[3]);
2324 idx++;
2325 }
2326 *match6_cnt = cnt;
2327 return addr_match6;
2328}
2329
2330/**
2331 * \internal
2332 * \brief build address match array for cache efficient matching
2333 *
2334 * \param s the signature
2335 */
2336static void SigBuildAddressMatchArray(Signature *s)
2337{
2338 /* source addresses */
2339 s->addr_src_match4 =
2340 SigBuildAddressMatchArrayIPv4(s->init_data->src->ipv4_head, &s->addr_src_match4_cnt);
2341 /* destination addresses */
2342 s->addr_dst_match4 =
2343 SigBuildAddressMatchArrayIPv4(s->init_data->dst->ipv4_head, &s->addr_dst_match4_cnt);
2344
2345 /* source addresses IPv6 */
2346 s->addr_src_match6 =
2347 SigBuildAddressMatchArrayIPv6(s->init_data->src->ipv6_head, &s->addr_src_match6_cnt);
2348 /* destination addresses IPv6 */
2349 s->addr_dst_match6 =
2350 SigBuildAddressMatchArrayIPv6(s->init_data->dst->ipv6_head, &s->addr_dst_match6_cnt);
2351}
2352
2353static int SigMatchListLen(SigMatch *sm)
2354{
2355 int len = 0;
2356 for (; sm != NULL; sm = sm->next)
2357 len++;
2358
2359 return len;
2360}
2361
2362/** \brief convert SigMatch list to SigMatchData array
2363 * \note ownership of sm->ctx is transferred to smd->ctx
2364 */
2366{
2367 int len = SigMatchListLen(head);
2368 if (len == 0)
2369 return NULL;
2370
2372 if (smd == NULL) {
2373 FatalError("initializing the detection engine failed");
2374 }
2375 SigMatchData *out = smd;
2376
2377 /* Copy sm type and Context into array */
2378 SigMatch *sm = head;
2379 for (; sm != NULL; sm = sm->next, smd++) {
2380 smd->type = sm->type;
2381 smd->ctx = sm->ctx;
2382 sm->ctx = NULL; // SigMatch no longer owns the ctx
2383 smd->is_last = (sm->next == NULL);
2384 }
2385 return out;
2386}
2387
2388extern int g_skip_prefilter;
2389
2390static void SigSetupPrefilter(DetectEngineCtx *de_ctx, Signature *s)
2391{
2392 SCEnter();
2393 SCLogDebug("s %u: set up prefilter/mpm", s->id);
2395
2396 if (s->init_data->prefilter_sm != NULL) {
2399 if (s->init_data->mpm_sm != NULL) {
2401 SCLogDebug("%u: RetrieveFPForSig set", s->id);
2402 SCReturn;
2403 }
2404 /* fall through, this can happen if the mpm doesn't support the pattern */
2405 } else {
2407 SCReturn;
2408 }
2409 } else {
2410 SCLogDebug("%u: RetrieveFPForSig", s->id);
2412 if (s->init_data->mpm_sm != NULL) {
2414 SCLogDebug("%u: RetrieveFPForSig set", s->id);
2415 SCReturn;
2416 }
2417 }
2418
2419 SCLogDebug("s %u: no mpm; prefilter? de_ctx->prefilter_setting %u "
2420 "s->init_data->has_possible_prefilter %s",
2422
2424 SCReturn;
2425
2428 int prefilter_list = DETECT_TBLSIZE;
2429 /* get the keyword supporting prefilter with the lowest type */
2430 for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
2431 for (SigMatch *sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
2432 if (sigmatch_table[sm->type].SupportsPrefilter != NULL) {
2434 prefilter_list = MIN(prefilter_list, sm->type);
2435 }
2436 }
2437 }
2438 }
2439
2440 /* apply that keyword as prefilter */
2441 if (prefilter_list != DETECT_TBLSIZE) {
2442 for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
2443 for (SigMatch *sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
2444 if (sm->type == prefilter_list) {
2445 s->init_data->prefilter_sm = sm;
2447 SCLogConfig("sid %u: prefilter is on \"%s\"", s->id,
2448 sigmatch_table[sm->type].name);
2449 break;
2450 }
2451 }
2452 }
2453 }
2454 }
2455 SCReturn;
2456}
2457
2458/** \internal
2459 * \brief check if signature's table requirement is supported by each of the keywords it uses.
2460 */
2461static bool DetectRuleValidateTable(const Signature *s)
2462{
2463 if (s->detect_table == 0)
2464 return true;
2465
2466 const uint8_t table_as_flag = BIT_U8(s->detect_table);
2467
2468 for (SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) {
2469 const uint8_t kw_tables_supported = sigmatch_table[sm->type].tables;
2470 if (kw_tables_supported != 0 && (kw_tables_supported & table_as_flag) == 0) {
2471 SCLogError("rule %u uses hook \"%s\", but keyword \"%s\" doesn't support this hook",
2473 return false;
2474 }
2475 }
2476 return true;
2477}
2478
2479static bool DetectFirewallRuleValidate(const DetectEngineCtx *de_ctx, const Signature *s)
2480{
2482 SCLogError("rule %u is loaded as a firewall rule, but does not specify an "
2483 "explicit hook",
2484 s->id);
2485 return false;
2486 }
2487 return true;
2488}
2489
2490static void DetectRuleSetTable(Signature *s)
2491{
2492 enum DetectTable table;
2493 if (s->flags & SIG_FLAG_FIREWALL) {
2494 if (s->type == SIG_TYPE_PKT) {
2498 else if (s->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT &&
2501 else
2503 } else if (s->type == SIG_TYPE_APP_TX) {
2505 } else {
2506 BUG_ON(1);
2507 }
2508 } else {
2509 // TODO pre_flow/pre_stream
2510 if (s->type != SIG_TYPE_APP_TX) {
2511 table = DETECT_TABLE_PACKET_TD;
2512 } else {
2513 table = DETECT_TABLE_APP_TD;
2514 }
2515 }
2516
2517 s->detect_table = (uint8_t)table;
2518}
2519
2520static int SigValidateFirewall(const DetectEngineCtx *de_ctx, const Signature *s)
2521{
2522 if (s->init_data->firewall_rule) {
2523 if (!DetectFirewallRuleValidate(de_ctx, s))
2524 SCReturnInt(0);
2525 }
2526 SCReturnInt(1);
2527}
2528
2529static int SigValidateCheckBuffers(
2530 DetectEngineCtx *de_ctx, const Signature *s, int *ts_excl, int *tc_excl, int *dir_amb)
2531{
2532 bool has_frame = false;
2533 bool has_app = false;
2534 bool has_pkt = false;
2535 bool has_pmatch = false;
2536
2537 int nlists = 0;
2538 for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2539 nlists = MAX(nlists, (int)s->init_data->buffers[x].id);
2540 }
2541 nlists += (nlists > 0);
2542 SCLogDebug("nlists %d", nlists);
2543
2544 if (s->init_data->curbuf && s->init_data->curbuf->head == NULL) {
2545 SCLogError("rule %u setup buffer %s but didn't add matches to it", s->id,
2547 SCReturnInt(0);
2548 }
2549
2550 /* run buffer type validation callbacks if any */
2553 SCReturnInt(0);
2554
2555 has_pmatch = true;
2556 }
2557
2558 struct BufferVsDir {
2559 int ts;
2560 int tc;
2561 } bufdir[nlists + 1];
2562 memset(&bufdir, 0, (nlists + 1) * sizeof(struct BufferVsDir));
2563
2564 for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2567 if (bt == NULL) {
2568 DEBUG_VALIDATE_BUG_ON(1); // should be impossible
2569 continue;
2570 }
2571 SCLogDebug("x %u b->id %u name %s", x, b->id, bt->name);
2572 for (const SigMatch *sm = b->head; sm != NULL; sm = sm->next) {
2573 SCLogDebug("sm %u %s", sm->type, sigmatch_table[sm->type].name);
2574 }
2575
2576 if (b->head == NULL) {
2577 SCLogError("no matches in sticky buffer %s", bt->name);
2578 SCReturnInt(0);
2579 }
2580
2581 has_frame |= bt->frame;
2582 has_app |= (!bt->frame && !bt->packet);
2583 has_pkt |= bt->packet;
2584
2585 if ((s->flags & SIG_FLAG_REQUIRE_PACKET) && !bt->packet) {
2586 SCLogError("Signature combines packet "
2587 "specific matches (like dsize, flags, ttl) with stream / "
2588 "state matching by matching on app layer proto (like using "
2589 "http_* keywords).");
2590 SCReturnInt(0);
2591 }
2592
2594 for (; app != NULL; app = app->next) {
2595 if (app->sm_list == b->id &&
2596 (AppProtoEquals(s->alproto, app->alproto) || s->alproto == 0)) {
2597 SCLogDebug("engine %s dir %d alproto %d",
2599 app->alproto);
2600 SCLogDebug("b->id %d nlists %d", b->id, nlists);
2601
2602 if (b->only_tc) {
2603 if (app->dir == 1)
2604 (*tc_excl)++;
2605 } else if (b->only_ts) {
2606 if (app->dir == 0)
2607 (*ts_excl)++;
2608 } else {
2609 bufdir[b->id].ts += (app->dir == 0);
2610 bufdir[b->id].tc += (app->dir == 1);
2611 }
2612
2613 /* only allow rules to use the hook for engines at that
2614 * exact progress for now. */
2616 if ((s->flags & SIG_FLAG_TOSERVER) && (app->dir == 0) &&
2617 app->progress != s->init_data->hook.t.app.app_progress) {
2618 SCLogError("engine progress value %d doesn't match hook %u", app->progress,
2620 SCReturnInt(0);
2621 }
2622 if ((s->flags & SIG_FLAG_TOCLIENT) && (app->dir == 1) &&
2623 app->progress != s->init_data->hook.t.app.app_progress) {
2624 SCLogError("engine progress value doesn't match hook");
2625 SCReturnInt(0);
2626 }
2627 }
2628 }
2629 }
2630
2632 SCReturnInt(0);
2633 }
2634
2636 SCReturnInt(0);
2637 }
2639 SCReturnInt(0);
2640 }
2641 }
2642
2643 if (has_pmatch && has_frame) {
2644 SCLogError("can't mix pure content and frame inspection");
2645 SCReturnInt(0);
2646 }
2647 if (has_app && has_frame) {
2648 SCLogError("can't mix app-layer buffer and frame inspection");
2649 SCReturnInt(0);
2650 }
2651 if (has_pkt && has_frame) {
2652 SCLogError("can't mix pkt buffer and frame inspection");
2653 SCReturnInt(0);
2654 }
2655
2656 for (int x = 0; x < nlists; x++) {
2657 if (bufdir[x].ts == 0 && bufdir[x].tc == 0)
2658 continue;
2659 (*ts_excl) += (bufdir[x].ts > 0 && bufdir[x].tc == 0);
2660 (*tc_excl) += (bufdir[x].ts == 0 && bufdir[x].tc > 0);
2661 (*dir_amb) += (bufdir[x].ts > 0 && bufdir[x].tc > 0);
2662
2663 SCLogDebug("%s/%d: %d/%d", DetectEngineBufferTypeGetNameById(de_ctx, x), x, bufdir[x].ts,
2664 bufdir[x].tc);
2665 }
2666
2667 SCReturnInt(1);
2668}
2669
2670static int SigValidatePacketStream(const Signature *s)
2671{
2673 SCLogError("can't mix packet keywords with "
2674 "tcp-stream or flow:only_stream. Invalidating signature.");
2675 SCReturnInt(0);
2676 }
2677 SCReturnInt(1);
2678}
2679
2680static int SigConsolidateDirection(
2681 Signature *s, const int ts_excl, const int tc_excl, const int dir_amb)
2682{
2683 if (s->flags & SIG_FLAG_TXBOTHDIR) {
2684 if (!ts_excl || !tc_excl) {
2685 SCLogError("rule %u should use both directions, but does not", s->id);
2686 SCReturnInt(0);
2687 }
2688 if (dir_amb) {
2689 SCLogError("rule %u means to use both directions, cannot have keywords ambiguous about "
2690 "directions",
2691 s->id);
2692 SCReturnInt(0);
2693 }
2694 } else if (ts_excl && tc_excl) {
2695 SCLogError(
2696 "rule %u mixes keywords with conflicting directions, a transactional rule with => "
2697 "should be used",
2698 s->id);
2699 SCReturnInt(0);
2700 } else if (ts_excl) {
2701 SCLogDebug("%u: implied rule direction is toserver", s->id);
2703 SCLogError("rule %u mixes keywords with conflicting directions", s->id);
2704 SCReturnInt(0);
2705 }
2706 } else if (tc_excl) {
2707 SCLogDebug("%u: implied rule direction is toclient", s->id);
2709 SCLogError("rule %u mixes keywords with conflicting directions", s->id);
2710 SCReturnInt(0);
2711 }
2712 } else if (dir_amb) {
2713 SCLogDebug("%u: rule direction cannot be deduced from keywords", s->id);
2714 }
2715 SCReturnInt(1);
2716}
2717
2718static void SigConsolidateTcpBuffer(Signature *s)
2719{
2720 /* TCP: corner cases:
2721 * - pkt vs stream vs depth/offset
2722 * - pkt vs stream vs stream_size
2723 */
2724 if (s->proto.proto[IPPROTO_TCP / 8] & (1 << (IPPROTO_TCP % 8))) {
2728 for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; sm != NULL;
2729 sm = sm->next) {
2730 if (sm->type == DETECT_CONTENT &&
2731 (((DetectContentData *)(sm->ctx))->flags &
2734 break;
2735 }
2736 }
2737 /* if stream_size is in use, also inspect packets */
2738 for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL;
2739 sm = sm->next) {
2740 if (sm->type == DETECT_STREAM_SIZE) {
2742 break;
2743 }
2744 }
2745 }
2746 }
2747 }
2748}
2749
2750static bool SigInspectsFiles(const Signature *s)
2751{
2752 return ((s->flags & SIG_FLAG_FILESTORE) || s->file_flags != 0 ||
2754}
2755
2756/** \internal
2757 * \brief validate file handling
2758 * \retval 1 good signature
2759 * \retval 0 bad signature
2760 */
2761static int SigValidateFileHandling(const Signature *s)
2762{
2763 if (!SigInspectsFiles(s)) {
2764 SCReturnInt(1);
2765 }
2766
2767 if (s->alproto != ALPROTO_UNKNOWN && !AppLayerParserSupportsFiles(IPPROTO_TCP, s->alproto)) {
2768 SCLogError("protocol %s doesn't "
2769 "support file matching",
2771 SCReturnInt(0);
2772 }
2773 if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
2774 bool found = false;
2775 for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2776 if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2777 break;
2778 }
2779 if (AppLayerParserSupportsFiles(IPPROTO_TCP, s->init_data->alprotos[i])) {
2780 found = true;
2781 break;
2782 }
2783 }
2784 if (!found) {
2785 SCLogError("No protocol support file matching");
2786 SCReturnInt(0);
2787 }
2788 }
2790 SCLogError("protocol HTTP2 doesn't support file name matching");
2791 SCReturnInt(0);
2792 }
2793 SCReturnInt(1);
2794}
2795
2796/**
2797 * \internal
2798 * \brief validate and consolidate parsed signature
2799 *
2800 * \param de_ctx detect engine
2801 * \param s signature to validate and consolidate
2802 *
2803 * \retval 0 invalid
2804 * \retval 1 valid
2805 */
2806static int SigValidateConsolidate(
2807 DetectEngineCtx *de_ctx, Signature *s, const SignatureParser *parser, const uint8_t dir)
2808{
2809 SCEnter();
2810
2811 if (SigValidateFirewall(de_ctx, s) == 0)
2812 SCReturnInt(0);
2813
2814 if (SigValidatePacketStream(s) == 0) {
2815 SCReturnInt(0);
2816 }
2817
2818 int ts_excl = 0;
2819 int tc_excl = 0;
2820 int dir_amb = 0;
2821
2822 if (SigValidateCheckBuffers(de_ctx, s, &ts_excl, &tc_excl, &dir_amb) == 0) {
2823 SCReturnInt(0);
2824 }
2825
2826 if (SigConsolidateDirection(s, ts_excl, tc_excl, dir_amb) == 0) {
2827 SCReturnInt(0);
2828 }
2829
2830 SigConsolidateTcpBuffer(s);
2831
2833 DetectRuleSetTable(s);
2834
2835 int r = SigValidateFileHandling(s);
2836 if (r == 0) {
2837 SCReturnInt(0);
2838 }
2839 if (SigInspectsFiles(s)) {
2840 if (s->alproto == ALPROTO_HTTP1 || s->alproto == ALPROTO_HTTP) {
2842 }
2843 }
2844 if (DetectRuleValidateTable(s) == false) {
2845 SCReturnInt(0);
2846 }
2847
2848 if (s->type == SIG_TYPE_IPONLY) {
2849 /* For IPOnly */
2850 if (IPOnlySigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ dir) < 0)
2851 SCReturnInt(0);
2852
2853 if (IPOnlySigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ dir) < 0)
2854 SCReturnInt(0);
2855 }
2856 SCReturnInt(1);
2857}
2858
2859/**
2860 * \internal
2861 * \brief Helper function for SigInit().
2862 */
2863static Signature *SigInitHelper(
2864 DetectEngineCtx *de_ctx, const char *sigstr, uint8_t dir, const bool firewall_rule)
2865{
2866 SignatureParser parser;
2867 memset(&parser, 0x00, sizeof(parser));
2868
2869 Signature *sig = SigAlloc();
2870 if (sig == NULL)
2871 goto error;
2872 if (firewall_rule) {
2873 sig->init_data->firewall_rule = true;
2874 sig->flags |= SIG_FLAG_FIREWALL;
2875 }
2876
2877 sig->sig_str = SCStrdup(sigstr);
2878 if (unlikely(sig->sig_str == NULL)) {
2879 goto error;
2880 }
2881
2882 /* default gid to 1 */
2883 sig->gid = 1;
2884
2885 /* We do a first parse of the rule in a requires, or scan-only
2886 * mode. Syntactic errors will be picked up here, but the only
2887 * part of the rule that is validated completely is the "requires"
2888 * keyword. */
2889 int ret = SigParse(de_ctx, sig, sigstr, dir, &parser, true);
2890 if (ret == -4) {
2891 /* Rule requirements not met. */
2892 de_ctx->sigerror_silent = true;
2893 de_ctx->sigerror_ok = true;
2894 de_ctx->sigerror_requires = true;
2895 goto error;
2896 } else if (ret < 0) {
2897 goto error;
2898 }
2899
2900 /* Check for a SID before continuuing. */
2901 if (sig->id == 0) {
2902 SCLogError("Signature missing required value \"sid\".");
2903 goto error;
2904 }
2905
2906 /* Now completely parse the rule. */
2907 ret = SigParse(de_ctx, sig, sigstr, dir, &parser, false);
2908 BUG_ON(ret == -4);
2909 if (ret == -3) {
2910 de_ctx->sigerror_silent = true;
2911 de_ctx->sigerror_ok = true;
2912 goto error;
2913 } else if (ret == -2) {
2914 de_ctx->sigerror_silent = true;
2915 goto error;
2916 } else if (ret < 0) {
2917 goto error;
2918 }
2919
2920 /* signature priority hasn't been overwritten. Using default priority */
2921 if (sig->prio == -1)
2923
2924 sig->iid = de_ctx->signum;
2925 de_ctx->signum++;
2926
2927 if (sig->alproto != ALPROTO_UNKNOWN) {
2928 int override_needed = 0;
2929 if (sig->proto.flags & DETECT_PROTO_ANY) {
2930 sig->proto.flags &= ~DETECT_PROTO_ANY;
2931 memset(sig->proto.proto, 0x00, sizeof(sig->proto.proto));
2932 override_needed = 1;
2933 } else {
2934 override_needed = 1;
2935 size_t s = 0;
2936 for (s = 0; s < sizeof(sig->proto.proto); s++) {
2937 if (sig->proto.proto[s] != 0x00) {
2938 override_needed = 0;
2939 break;
2940 }
2941 }
2942 }
2943
2944 /* at this point if we had alert ip and the ip proto was not
2945 * overridden, we use the ip proto that has been configured
2946 * against the app proto in use. */
2947 if (override_needed)
2949 }
2950
2951 /* set the packet and app layer flags, but only if the
2952 * app layer flag wasn't already set in which case we
2953 * only consider the app layer */
2954 if (!(sig->flags & SIG_FLAG_APPLAYER)) {
2955 if (sig->init_data->smlists[DETECT_SM_LIST_MATCH] != NULL) {
2957 for ( ; sm != NULL; sm = sm->next) {
2958 if (sigmatch_table[sm->type].Match != NULL)
2960 }
2961 } else {
2963 }
2964 }
2965
2968 if ((sig->flags & SIG_FLAG_TOSERVER) != 0) {
2970 }
2971 }
2972 }
2973
2974 if (!(sig->init_data->init_flags & SIG_FLAG_INIT_FLOW)) {
2975 if ((sig->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) {
2976 sig->flags |= SIG_FLAG_TOSERVER;
2977 sig->flags |= SIG_FLAG_TOCLIENT;
2978 }
2979 }
2980
2981 SCLogDebug("sig %"PRIu32" SIG_FLAG_APPLAYER: %s, SIG_FLAG_PACKET: %s",
2982 sig->id, sig->flags & SIG_FLAG_APPLAYER ? "set" : "not set",
2983 sig->init_data->init_flags & SIG_FLAG_INIT_PACKET ? "set" : "not set");
2984
2985 SigBuildAddressMatchArray(sig);
2986
2987 /* run buffer type callbacks if any */
2988 for (uint32_t x = 0; x < DETECT_SM_LIST_MAX; x++) {
2989 if (sig->init_data->smlists[x])
2991 }
2992 for (uint32_t x = 0; x < sig->init_data->buffer_index; x++) {
2994 }
2995
2996 SigSetupPrefilter(de_ctx, sig);
2997
2998 /* validate signature, SigValidate will report the error reason */
2999 if (SigValidateConsolidate(de_ctx, sig, &parser, dir) == 0) {
3000 goto error;
3001 }
3002
3003 return sig;
3004
3005error:
3006 if (sig != NULL) {
3007 SigFree(de_ctx, sig);
3008 }
3009 return NULL;
3010}
3011
3012/**
3013 * \brief Checks if a signature has the same source and destination
3014 * \param s parsed signature
3015 *
3016 * \retval true if source and destination are the same, false otherwise
3017 */
3018static bool SigHasSameSourceAndDestination(const Signature *s)
3019{
3020 if (!(s->flags & SIG_FLAG_SP_ANY) || !(s->flags & SIG_FLAG_DP_ANY)) {
3021 if (!DetectPortListsAreEqual(s->sp, s->dp)) {
3022 return false;
3023 }
3024 }
3025
3026 if (!(s->flags & SIG_FLAG_SRC_ANY) || !(s->flags & SIG_FLAG_DST_ANY)) {
3029
3031 return false;
3032 }
3033
3034 src = s->init_data->src->ipv6_head;
3035 dst = s->init_data->dst->ipv6_head;
3036
3038 return false;
3039 }
3040 }
3041
3042 return true;
3043}
3044
3045static Signature *SigInitDo(DetectEngineCtx *de_ctx, const char *sigstr, const bool firewall_rule)
3046{
3047 SCEnter();
3048
3049 uint32_t oldsignum = de_ctx->signum;
3050 de_ctx->sigerror_ok = false;
3051 de_ctx->sigerror_silent = false;
3052 de_ctx->sigerror_requires = false;
3053
3054 Signature *sig = SigInitHelper(de_ctx, sigstr, SIG_DIREC_NORMAL, firewall_rule);
3055 if (sig == NULL) {
3056 goto error;
3057 }
3058
3060 if (SigHasSameSourceAndDestination(sig)) {
3061 SCLogInfo("Rule with ID %u is bidirectional, but source and destination are the same, "
3062 "treating the rule as unidirectional", sig->id);
3063
3064 sig->init_data->init_flags &= ~SIG_FLAG_INIT_BIDIREC;
3065 } else {
3066 sig->next = SigInitHelper(de_ctx, sigstr, SIG_DIREC_SWITCHED, firewall_rule);
3067 if (sig->next == NULL) {
3068 goto error;
3069 }
3070 }
3071 }
3072
3073 SCReturnPtr(sig, "Signature");
3074
3075error:
3076 if (sig != NULL) {
3077 SigFree(de_ctx, sig);
3078 }
3079 /* if something failed, restore the old signum count
3080 * since we didn't install it */
3081 de_ctx->signum = oldsignum;
3082
3083 SCReturnPtr(NULL, "Signature");
3084}
3085
3086/**
3087 * \brief Parses a signature and adds it to the Detection Engine Context.
3088 *
3089 * \param de_ctx Pointer to the Detection Engine Context.
3090 * \param sigstr Pointer to a character string containing the signature to be
3091 * parsed.
3092 *
3093 * \retval Pointer to the Signature instance on success; NULL on failure.
3094 */
3096{
3097 return SigInitDo(de_ctx, sigstr, false);
3098}
3099
3100static Signature *DetectFirewallRuleNew(DetectEngineCtx *de_ctx, const char *sigstr)
3101{
3102 return SigInitDo(de_ctx, sigstr, true);
3103}
3104
3105/**
3106 * \brief The hash free function to be the used by the hash table -
3107 * DetectEngineCtx->dup_sig_hash_table.
3108 *
3109 * \param data Pointer to the data, in our case SigDuplWrapper to be freed.
3110 */
3111static void DetectParseDupSigFreeFunc(void *data)
3112{
3113 if (data != NULL)
3114 SCFree(data);
3115}
3116
3117/**
3118 * \brief The hash function to be the used by the hash table -
3119 * DetectEngineCtx->dup_sig_hash_table.
3120 *
3121 * \param ht Pointer to the hash table.
3122 * \param data Pointer to the data, in our case SigDuplWrapper.
3123 * \param datalen Not used in our case.
3124 *
3125 * \retval sw->s->id The generated hash value.
3126 */
3127static uint32_t DetectParseDupSigHashFunc(HashListTable *ht, void *data, uint16_t datalen)
3128{
3129 SigDuplWrapper *sw = (SigDuplWrapper *)data;
3130
3131 return (sw->s->id % ht->array_size);
3132}
3133
3134/**
3135 * \brief The Compare function to be used by the hash table -
3136 * DetectEngineCtx->dup_sig_hash_table.
3137 *
3138 * \param data1 Pointer to the first SigDuplWrapper.
3139 * \param len1 Not used.
3140 * \param data2 Pointer to the second SigDuplWrapper.
3141 * \param len2 Not used.
3142 *
3143 * \retval 1 If the 2 SigDuplWrappers sent as args match.
3144 * \retval 0 If the 2 SigDuplWrappers sent as args do not match.
3145 */
3146static char DetectParseDupSigCompareFunc(void *data1, uint16_t len1, void *data2,
3147 uint16_t len2)
3148{
3149 SigDuplWrapper *sw1 = (SigDuplWrapper *)data1;
3150 SigDuplWrapper *sw2 = (SigDuplWrapper *)data2;
3151
3152 if (sw1 == NULL || sw2 == NULL ||
3153 sw1->s == NULL || sw2->s == NULL)
3154 return 0;
3155
3156 /* sid and gid match required */
3157 if (sw1->s->id == sw2->s->id && sw1->s->gid == sw2->s->gid) return 1;
3158
3159 return 0;
3160}
3161
3162/**
3163 * \brief Initializes the hash table that is used to cull duplicate sigs.
3164 *
3165 * \param de_ctx Pointer to the detection engine context.
3166 *
3167 * \retval 0 On success.
3168 * \retval -1 On failure.
3169 */
3171{
3173 DetectParseDupSigHashFunc,
3174 DetectParseDupSigCompareFunc,
3175 DetectParseDupSigFreeFunc);
3176 if (de_ctx->dup_sig_hash_table == NULL)
3177 return -1;
3178
3179 return 0;
3180}
3181
3182/**
3183 * \brief Frees the hash table that is used to cull duplicate sigs.
3184 *
3185 * \param de_ctx Pointer to the detection engine context that holds this table.
3186 */
3194
3195/**
3196 * \brief Check if a signature is a duplicate.
3197 *
3198 * There are 3 types of return values for this function.
3199 *
3200 * - 0, which indicates that the Signature is not a duplicate
3201 * and has to be added to the detection engine list.
3202 * - 1, Signature is duplicate, and the existing signature in
3203 * the list shouldn't be replaced with this duplicate.
3204 * - 2, Signature is duplicate, and the existing signature in
3205 * the list should be replaced with this duplicate.
3206 *
3207 * \param de_ctx Pointer to the detection engine context.
3208 * \param sig Pointer to the Signature that has to be checked.
3209 *
3210 * \retval 2 If Signature is duplicate and the existing signature in
3211 * the list should be chucked out and replaced with this.
3212 * \retval 1 If Signature is duplicate, and should be chucked out.
3213 * \retval 0 If Signature is not a duplicate.
3214 */
3215static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx,
3216 Signature *sig)
3217{
3218 /* we won't do any NULL checks on the args */
3219
3220 /* return value */
3221 int ret = 0;
3222
3223 SigDuplWrapper *sw_dup = NULL;
3224 SigDuplWrapper *sw = NULL;
3225
3226 /* used for making a duplicate_sig_hash_table entry */
3227 sw = SCCalloc(1, sizeof(SigDuplWrapper));
3228 if (unlikely(sw == NULL)) {
3229 exit(EXIT_FAILURE);
3230 }
3231 sw->s = sig;
3232
3233 /* check if we have a duplicate entry for this signature */
3234 sw_dup = HashListTableLookup(de_ctx->dup_sig_hash_table, (void *)sw, 0);
3235 /* we don't have a duplicate entry for this sig */
3236 if (sw_dup == NULL) {
3237 /* add it to the hash table */
3239
3240 /* add the s_prev entry for the previously loaded sw in the hash_table */
3241 if (de_ctx->sig_list != NULL) {
3242 SigDuplWrapper *sw_old = NULL;
3243 SigDuplWrapper sw_tmp;
3244 memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
3245
3246 /* the topmost sig would be the last loaded sig */
3247 sw_tmp.s = de_ctx->sig_list;
3249 (void *)&sw_tmp, 0);
3250 /* sw_old == NULL case is impossible */
3251 sw_old->s_prev = sig;
3252 }
3253
3254 ret = 0;
3255 goto end;
3256 }
3257
3258 /* if we have reached here we have a duplicate entry for this signature.
3259 * Check the signature revision. Store the signature with the latest rev
3260 * and discard the other one */
3261 if (sw->s->rev <= sw_dup->s->rev) {
3262 ret = 1;
3263 SCFree(sw);
3264 sw = NULL;
3265 goto end;
3266 }
3267
3268 /* the new sig is of a newer revision than the one that is already in the
3269 * list. Remove the old sig from the list */
3270 if (sw_dup->s_prev == NULL) {
3271 SigDuplWrapper sw_temp;
3272 memset(&sw_temp, 0, sizeof(SigDuplWrapper));
3273 if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
3274 sw_temp.s = sw_dup->s->next->next;
3275 de_ctx->sig_list = sw_dup->s->next->next;
3276 SigFree(de_ctx, sw_dup->s->next);
3277 } else {
3278 sw_temp.s = sw_dup->s->next;
3279 de_ctx->sig_list = sw_dup->s->next;
3280 }
3281 SigDuplWrapper *sw_next = NULL;
3282 if (sw_temp.s != NULL) {
3284 (void *)&sw_temp, 0);
3285 sw_next->s_prev = sw_dup->s_prev;
3286 }
3287 SigFree(de_ctx, sw_dup->s);
3288 } else {
3289 SigDuplWrapper sw_temp;
3290 memset(&sw_temp, 0, sizeof(SigDuplWrapper));
3291 if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
3292 sw_temp.s = sw_dup->s->next->next;
3293 /* If previous signature is bidirectional,
3294 * it has 2 items in the linked list.
3295 * So we need to change next->next instead of next
3296 */
3298 sw_dup->s_prev->next->next = sw_dup->s->next->next;
3299 } else {
3300 sw_dup->s_prev->next = sw_dup->s->next->next;
3301 }
3302 SigFree(de_ctx, sw_dup->s->next);
3303 } else {
3304 sw_temp.s = sw_dup->s->next;
3306 sw_dup->s_prev->next->next = sw_dup->s->next;
3307 } else {
3308 sw_dup->s_prev->next = sw_dup->s->next;
3309 }
3310 }
3311 SigDuplWrapper *sw_next = NULL;
3312 if (sw_temp.s != NULL) {
3314 (void *)&sw_temp, 0);
3315 sw_next->s_prev = sw_dup->s_prev;
3316 }
3317 SigFree(de_ctx, sw_dup->s);
3318 }
3319
3320 /* make changes to the entry to reflect the presence of the new sig */
3321 sw_dup->s = sig;
3322 sw_dup->s_prev = NULL;
3323
3324 if (de_ctx->sig_list != NULL) {
3325 SigDuplWrapper sw_tmp;
3326 memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
3327 sw_tmp.s = de_ctx->sig_list;
3329 (void *)&sw_tmp, 0);
3330 if (sw_old->s != sw_dup->s) {
3331 // Link on top of the list if there was another element
3332 sw_old->s_prev = sig;
3333 }
3334 }
3335
3336 /* this is duplicate, but a duplicate that replaced the existing sig entry */
3337 ret = 2;
3338
3339 SCFree(sw);
3340
3341end:
3342 return ret;
3343}
3344
3345/**
3346 * \brief Parse and append a Signature into the Detection Engine Context
3347 * signature list.
3348 *
3349 * If the signature is bidirectional it should append two signatures
3350 * (with the addresses switched) into the list. Also handle duplicate
3351 * signatures. In case of duplicate sigs, use the ones that have the
3352 * latest revision. We use the sid and the msg to identify duplicate
3353 * sigs. If 2 sigs have the same sid and gid, they are duplicates.
3354 *
3355 * \param de_ctx Pointer to the Detection Engine Context.
3356 * \param sigstr Pointer to a character string containing the signature to be
3357 * parsed.
3358 * \param sig_file Pointer to a character string containing the filename from
3359 * which signature is read
3360 * \param lineno Line number from where signature is read
3361 *
3362 * \retval Pointer to the head Signature in the detection engine ctx sig_list
3363 * on success; NULL on failure.
3364 */
3366{
3367 Signature *sig = DetectFirewallRuleNew(de_ctx, sigstr);
3368 if (sig == NULL) {
3369 return NULL;
3370 }
3371
3372 /* checking for the status of duplicate signature */
3373 int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig);
3374 /* a duplicate signature that should be chucked out. Check the previously
3375 * called function details to understand the different return values */
3376 if (dup_sig == 1) {
3377 SCLogError("Duplicate signature \"%s\"", sigstr);
3378 goto error;
3379 } else if (dup_sig == 2) {
3380 SCLogWarning("Signature with newer revision,"
3381 " so the older sig replaced by this new signature \"%s\"",
3382 sigstr);
3383 }
3384
3386 if (sig->next != NULL) {
3387 sig->next->next = de_ctx->sig_list;
3388 } else {
3389 goto error;
3390 }
3391 } else {
3392 /* if this sig is the first one, sig_list should be null */
3393 sig->next = de_ctx->sig_list;
3394 }
3395
3396 de_ctx->sig_list = sig;
3397
3398 /**
3399 * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one
3400 * so if the signature is bidirectional, the returned sig will point through "next" ptr
3401 * to the cloned signatures with the switched addresses
3402 */
3403 return (dup_sig == 0 || dup_sig == 2) ? sig : NULL;
3404
3405error:
3406 /* free the 2nd sig bidir may have set up */
3407 if (sig != NULL && sig->next != NULL) {
3408 SigFree(de_ctx, sig->next);
3409 sig->next = NULL;
3410 }
3411 if (sig != NULL) {
3412 SigFree(de_ctx, sig);
3413 }
3414 return NULL;
3415}
3416
3417/**
3418 * \brief Parse and append a Signature into the Detection Engine Context
3419 * signature list.
3420 *
3421 * If the signature is bidirectional it should append two signatures
3422 * (with the addresses switched) into the list. Also handle duplicate
3423 * signatures. In case of duplicate sigs, use the ones that have the
3424 * latest revision. We use the sid and the msg to identify duplicate
3425 * sigs. If 2 sigs have the same sid and gid, they are duplicates.
3426 *
3427 * \param de_ctx Pointer to the Detection Engine Context.
3428 * \param sigstr Pointer to a character string containing the signature to be
3429 * parsed.
3430 * \param sig_file Pointer to a character string containing the filename from
3431 * which signature is read
3432 * \param lineno Line number from where signature is read
3433 *
3434 * \retval Pointer to the head Signature in the detection engine ctx sig_list
3435 * on success; NULL on failure.
3436 */
3438{
3439 Signature *sig = SigInit(de_ctx, sigstr);
3440 if (sig == NULL) {
3441 return NULL;
3442 }
3443
3444 /* checking for the status of duplicate signature */
3445 int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig);
3446 /* a duplicate signature that should be chucked out. Check the previously
3447 * called function details to understand the different return values */
3448 if (dup_sig == 1) {
3449 SCLogError("Duplicate signature \"%s\"", sigstr);
3450 goto error;
3451 } else if (dup_sig == 2) {
3452 SCLogWarning("Signature with newer revision,"
3453 " so the older sig replaced by this new signature \"%s\"",
3454 sigstr);
3455 }
3456
3458 if (sig->next != NULL) {
3459 sig->next->next = de_ctx->sig_list;
3460 } else {
3461 goto error;
3462 }
3463 } else {
3464 /* if this sig is the first one, sig_list should be null */
3465 sig->next = de_ctx->sig_list;
3466 }
3467
3468 de_ctx->sig_list = sig;
3469
3470 /**
3471 * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one
3472 * so if the signature is bidirectional, the returned sig will point through "next" ptr
3473 * to the cloned signatures with the switched addresses
3474 */
3475 return (dup_sig == 0 || dup_sig == 2) ? sig : NULL;
3476
3477error:
3478 /* free the 2nd sig bidir may have set up */
3479 if (sig != NULL && sig->next != NULL) {
3480 SigFree(de_ctx, sig->next);
3481 sig->next = NULL;
3482 }
3483 if (sig != NULL) {
3484 SigFree(de_ctx, sig);
3485 }
3486 return NULL;
3487}
3488
3489static DetectParseRegex *g_detect_parse_regex_list = NULL;
3490
3491int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str,
3492 int start_offset, int options)
3493{
3494 *match = pcre2_match_data_create_from_pattern(parse_regex->regex, NULL);
3495 if (*match)
3496 return pcre2_match(parse_regex->regex, (PCRE2_SPTR8)str, strlen(str), options, start_offset,
3497 *match, parse_regex->context);
3498 return -1;
3499}
3500
3502{
3503 if (r->regex) {
3504 pcre2_code_free(r->regex);
3505 }
3506 if (r->context) {
3507 pcre2_match_context_free(r->context);
3508 }
3509}
3510
3512{
3513 DetectParseRegex *r = g_detect_parse_regex_list;
3514 while (r) {
3516
3518
3519 SCFree(r);
3520 r = next;
3521 }
3522 g_detect_parse_regex_list = NULL;
3523}
3524
3525/** \brief add regex and/or study to at exit free list
3526 */
3528{
3529 DetectParseRegex *r = SCCalloc(1, sizeof(*r));
3530 if (r == NULL) {
3531 FatalError("failed to alloc memory for pcre free list");
3532 }
3533 r->regex = detect_parse->regex;
3534 r->next = g_detect_parse_regex_list;
3535 g_detect_parse_regex_list = r;
3536}
3537
3538bool DetectSetupParseRegexesOpts(const char *parse_str, DetectParseRegex *detect_parse, int opts)
3539{
3540 int en;
3541 PCRE2_SIZE eo;
3542
3543 detect_parse->regex =
3544 pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
3545 if (detect_parse->regex == NULL) {
3546 PCRE2_UCHAR errbuffer[256];
3547 pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
3548 SCLogError("pcre compile of \"%s\" failed at "
3549 "offset %d: %s",
3550 parse_str, en, errbuffer);
3551 return false;
3552 }
3553 detect_parse->context = pcre2_match_context_create(NULL);
3554 if (detect_parse->context == NULL) {
3555 SCLogError("pcre2 could not create match context");
3556 pcre2_code_free(detect_parse->regex);
3557 detect_parse->regex = NULL;
3558 return false;
3559 }
3560 pcre2_set_match_limit(detect_parse->context, SC_MATCH_LIMIT_DEFAULT);
3561 pcre2_set_recursion_limit(detect_parse->context, SC_MATCH_LIMIT_RECURSION_DEFAULT);
3562 DetectParseRegexAddToFreeList(detect_parse);
3563
3564 return true;
3565}
3566
3567DetectParseRegex *DetectSetupPCRE2(const char *parse_str, int opts)
3568{
3569 int en;
3570 PCRE2_SIZE eo;
3571 DetectParseRegex *detect_parse = SCCalloc(1, sizeof(DetectParseRegex));
3572 if (detect_parse == NULL) {
3573 return NULL;
3574 }
3575
3576 detect_parse->regex =
3577 pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
3578 if (detect_parse->regex == NULL) {
3579 PCRE2_UCHAR errbuffer[256];
3580 pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
3581 SCLogError("pcre2 compile of \"%s\" failed at "
3582 "offset %d: %s",
3583 parse_str, (int)eo, errbuffer);
3584 SCFree(detect_parse);
3585 return NULL;
3586 }
3587
3588 detect_parse->next = g_detect_parse_regex_list;
3589 g_detect_parse_regex_list = detect_parse;
3590 return detect_parse;
3591}
3592
3594 pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR *buffer, PCRE2_SIZE *bufflen)
3595{
3596 int r = pcre2_substring_copy_bynumber(match_data, number, buffer, bufflen);
3597 if (r == PCRE2_ERROR_UNSET) {
3598 buffer[0] = 0;
3599 *bufflen = 0;
3600 return 0;
3601 }
3602 return r;
3603}
3604
3606 pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR **bufferptr, PCRE2_SIZE *bufflen)
3607{
3608 int r = pcre2_substring_get_bynumber(match_data, number, bufferptr, bufflen);
3609 if (r == PCRE2_ERROR_UNSET) {
3610 *bufferptr = NULL;
3611 *bufflen = 0;
3612 return 0;
3613 }
3614 return r;
3615}
3616
3617void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
3618{
3619 if (!DetectSetupParseRegexesOpts(parse_str, detect_parse, 0)) {
3620 FatalError("pcre compile and study failed");
3621 }
3622}
3623
3624/*
3625 * TESTS
3626 */
3627
3628#ifdef UNITTESTS
3629#include "detect-engine-alert.h"
3630#include "packet.h"
3631
3632static int SigParseTest01 (void)
3633{
3634 int result = 1;
3635 Signature *sig = NULL;
3636
3638 if (de_ctx == NULL)
3639 goto end;
3640
3641 sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
3642 if (sig == NULL)
3643 result = 0;
3644
3645end:
3646 if (sig != NULL) SigFree(de_ctx, sig);
3647 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3648 return result;
3649}
3650
3651static int SigParseTest02 (void)
3652{
3653 int result = 0;
3654 Signature *sig = NULL;
3655 DetectPort *port = NULL;
3656
3658
3659 if (de_ctx == NULL)
3660 goto end;
3661
3664
3665 sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"ET MALWARE Suspicious 220 Banner on Local Port\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; sid:2003055; rev:4;)");
3666 if (sig == NULL) {
3667 goto end;
3668 }
3669
3670 int r = DetectPortParse(de_ctx, &port, "0:20");
3671 if (r < 0)
3672 goto end;
3673
3674 if (DetectPortCmp(sig->sp, port) == PORT_EQ) {
3675 result = 1;
3676 } else {
3677 DetectPortPrint(port); printf(" != "); DetectPortPrint(sig->sp); printf(": ");
3678 }
3679
3680end:
3681 if (port != NULL)
3683 if (sig != NULL)
3684 SigFree(de_ctx, sig);
3685 if (de_ctx != NULL)
3687 return result;
3688}
3689
3690/**
3691 * \test SigParseTest03 test for invalid direction operator in rule
3692 */
3693static int SigParseTest03 (void)
3694{
3695 int result = 1;
3696 Signature *sig = NULL;
3697
3699 if (de_ctx == NULL)
3700 goto end;
3701
3702 sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any <- !1.2.3.4 any (msg:\"SigParseTest03\"; sid:1;)");
3703 if (sig != NULL) {
3704 result = 0;
3705 printf("expected NULL got sig ptr %p: ",sig);
3706 }
3707
3708end:
3709 if (sig != NULL) SigFree(de_ctx, sig);
3710 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3711 return result;
3712}
3713
3714static int SigParseTest04 (void)
3715{
3716 int result = 1;
3717 Signature *sig = NULL;
3718
3720 if (de_ctx == NULL)
3721 goto end;
3722
3723 sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024: -> !1.2.3.4 1024: (msg:\"SigParseTest04\"; sid:1;)");
3724 if (sig == NULL)
3725 result = 0;
3726
3727end:
3728 if (sig != NULL) SigFree(de_ctx, sig);
3729 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3730 return result;
3731}
3732
3733/** \test Port validation */
3734static int SigParseTest05 (void)
3735{
3736 int result = 0;
3737 Signature *sig = NULL;
3738
3740 if (de_ctx == NULL)
3741 goto end;
3742
3743 sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024:65536 -> !1.2.3.4 any (msg:\"SigParseTest05\"; sid:1;)");
3744 if (sig == NULL) {
3745 result = 1;
3746 } else {
3747 printf("signature didn't fail to parse as we expected: ");
3748 }
3749
3750end:
3751 if (sig != NULL) SigFree(de_ctx, sig);
3752 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3753 return result;
3754}
3755
3756/** \test Parsing bug debugging at 2010-03-18 */
3757static int SigParseTest06 (void)
3758{
3759 int result = 0;
3760 Signature *sig = NULL;
3761
3763 if (de_ctx == NULL)
3764 goto end;
3765
3766 sig = SigInit(de_ctx, "alert tcp any any -> any any (flow:to_server; content:\"GET\"; nocase; http_method; uricontent:\"/uri/\"; nocase; content:\"Host|3A| abc\"; nocase; sid:1; rev:1;)");
3767 if (sig != NULL) {
3768 result = 1;
3769 } else {
3770 printf("signature failed to parse: ");
3771 }
3772
3773end:
3774 if (sig != NULL)
3775 SigFree(de_ctx, sig);
3776 if (de_ctx != NULL)
3778 return result;
3779}
3780
3781/**
3782 * \test Parsing duplicate sigs.
3783 */
3784static int SigParseTest07(void)
3785{
3786 int result = 0;
3787
3789 if (de_ctx == NULL)
3790 goto end;
3791
3792 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3793 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3794
3795 result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL);
3796
3797end:
3798 if (de_ctx != NULL)
3800 return result;
3801}
3802
3803/**
3804 * \test Parsing duplicate sigs.
3805 */
3806static int SigParseTest08(void)
3807{
3808 int result = 0;
3809
3811 if (de_ctx == NULL)
3812 goto end;
3813
3814 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3815 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)");
3816
3817 result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL &&
3818 de_ctx->sig_list->rev == 2);
3819
3820end:
3821 if (de_ctx != NULL)
3823 return result;
3824}
3825
3826/**
3827 * \test Parsing duplicate sigs.
3828 */
3829static int SigParseTest09(void)
3830{
3831 int result = 1;
3832
3834 if (de_ctx == NULL)
3835 goto end;
3836
3837 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3838 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)");
3839 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:6;)");
3840 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:4;)");
3841 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)");
3842 result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
3843 de_ctx->sig_list->rev == 2);
3844 if (result == 0)
3845 goto end;
3846 result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
3847 de_ctx->sig_list->next->rev == 6);
3848 if (result == 0)
3849 goto end;
3850
3851 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
3852 result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
3853 de_ctx->sig_list->rev == 2);
3854 if (result == 0)
3855 goto end;
3856 result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
3857 de_ctx->sig_list->next->rev == 6);
3858 if (result == 0)
3859 goto end;
3860
3861 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:4;)");
3862 result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
3863 de_ctx->sig_list->rev == 4);
3864 if (result == 0)
3865 goto end;
3866 result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
3867 de_ctx->sig_list->next->rev == 6);
3868 if (result == 0)
3869 goto end;
3870
3871end:
3872 if (de_ctx != NULL)
3874 return result;
3875}
3876
3877/**
3878 * \test Parsing duplicate sigs.
3879 */
3880static int SigParseTest10(void)
3881{
3882 int result = 1;
3883
3885 if (de_ctx == NULL)
3886 goto end;
3887
3888 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3889 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
3890 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:1;)");
3891 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:4; rev:1;)");
3892 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:5; rev:1;)");
3893 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:2;)");
3894 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)");
3895
3896 result &= ((de_ctx->sig_list->id == 2) &&
3897 (de_ctx->sig_list->next->id == 3) &&
3898 (de_ctx->sig_list->next->next->id == 5) &&
3899 (de_ctx->sig_list->next->next->next->id == 4) &&
3900 (de_ctx->sig_list->next->next->next->next->id == 1));
3901
3902end:
3903 if (de_ctx != NULL)
3905 return result;
3906}
3907
3908/**
3909 * \test Parsing sig with trailing space(s) as reported by
3910 * Morgan Cox on oisf-users.
3911 */
3912static int SigParseTest11(void)
3913{
3914 int result = 0;
3915
3917 if (de_ctx == NULL)
3918 goto end;
3919
3920 Signature *s = NULL;
3921
3923 "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking the http link\"; sid:1;) ");
3924 if (s == NULL) {
3925 printf("sig 1 didn't parse: ");
3926 goto end;
3927 }
3928
3929 s = DetectEngineAppendSig(de_ctx, "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking "
3930 "the http link\"; sid:2;) ");
3931 if (s == NULL) {
3932 printf("sig 2 didn't parse: ");
3933 goto end;
3934 }
3935
3936 result = 1;
3937end:
3938 if (de_ctx != NULL)
3940 return result;
3941}
3942
3943/**
3944 * \test file_data with rawbytes
3945 */
3946static int SigParseTest12(void)
3947{
3948 int result = 0;
3949
3951 if (de_ctx == NULL)
3952 goto end;
3953
3954 Signature *s = NULL;
3955
3956 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (file_data; content:\"abc\"; rawbytes; sid:1;)");
3957 if (s != NULL) {
3958 printf("sig 1 should have given an error: ");
3959 goto end;
3960 }
3961
3962 result = 1;
3963end:
3964 if (de_ctx != NULL)
3966 return result;
3967}
3968
3969/**
3970 * \test packet/stream sig
3971 */
3972static int SigParseTest13(void)
3973{
3974 int result = 0;
3975
3977 if (de_ctx == NULL)
3978 goto end;
3979
3980 Signature *s = NULL;
3981
3982 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; sid:1;)");
3983 if (s == NULL) {
3984 printf("sig 1 invalidated: failure");
3985 goto end;
3986 }
3987
3988 if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
3989 printf("sig doesn't have stream flag set\n");
3990 goto end;
3991 }
3992
3993 if (s->flags & SIG_FLAG_REQUIRE_PACKET) {
3994 printf("sig has packet flag set\n");
3995 goto end;
3996 }
3997
3998 result = 1;
3999
4000end:
4001 if (de_ctx != NULL)
4003 return result;
4004}
4005
4006/**
4007 * \test packet/stream sig
4008 */
4009static int SigParseTest14(void)
4010{
4011 int result = 0;
4012
4014 if (de_ctx == NULL)
4015 goto end;
4016
4017 Signature *s = NULL;
4018
4019 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; dsize:>0; sid:1;)");
4020 if (s == NULL) {
4021 printf("sig 1 invalidated: failure");
4022 goto end;
4023 }
4024
4025 if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4026 printf("sig doesn't have packet flag set\n");
4027 goto end;
4028 }
4029
4030 if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
4031 printf("sig has stream flag set\n");
4032 goto end;
4033 }
4034
4035 result = 1;
4036
4037end:
4038 if (de_ctx != NULL)
4040 return result;
4041}
4042
4043/**
4044 * \test packet/stream sig
4045 */
4046static int SigParseTest15(void)
4047{
4048 int result = 0;
4049
4051 if (de_ctx == NULL)
4052 goto end;
4053
4054 Signature *s = NULL;
4055
4056 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:5; sid:1;)");
4057 if (s == NULL) {
4058 printf("sig 1 invalidated: failure");
4059 goto end;
4060 }
4061
4062 if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4063 printf("sig doesn't have packet flag set\n");
4064 goto end;
4065 }
4066
4067 if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4068 printf("sig doesn't have stream flag set\n");
4069 goto end;
4070 }
4071
4072 result = 1;
4073
4074end:
4075 if (de_ctx != NULL)
4077 return result;
4078}
4079
4080/**
4081 * \test packet/stream sig
4082 */
4083static int SigParseTest16(void)
4084{
4085 int result = 0;
4086
4088 if (de_ctx == NULL)
4089 goto end;
4090
4091 Signature *s = NULL;
4092
4093 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; depth:5; sid:1;)");
4094 if (s == NULL) {
4095 printf("sig 1 invalidated: failure");
4096 goto end;
4097 }
4098
4099 if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4100 printf("sig doesn't have packet flag set\n");
4101 goto end;
4102 }
4103
4104 if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4105 printf("sig doesn't have stream flag set\n");
4106 goto end;
4107 }
4108
4109 result = 1;
4110
4111end:
4112 if (de_ctx != NULL)
4114 return result;
4115}
4116
4117/**
4118 * \test packet/stream sig
4119 */
4120static int SigParseTest17(void)
4121{
4122 int result = 0;
4123
4125 if (de_ctx == NULL)
4126 goto end;
4127
4128 Signature *s = NULL;
4129
4130 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)");
4131 if (s == NULL) {
4132 printf("sig 1 invalidated: failure");
4133 goto end;
4134 }
4135
4136 if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4137 printf("sig doesn't have packet flag set\n");
4138 goto end;
4139 }
4140
4141 if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4142 printf("sig doesn't have stream flag set\n");
4143 goto end;
4144 }
4145
4146 result = 1;
4147
4148end:
4149 if (de_ctx != NULL)
4151 return result;
4152}
4153
4154/** \test sid value too large. Bug #779 */
4155static int SigParseTest18 (void)
4156{
4157 int result = 0;
4158
4160 if (de_ctx == NULL)
4161 goto end;
4162
4163 if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:99999999999999999999;)") != NULL)
4164 goto end;
4165
4166 result = 1;
4167end:
4168 if (de_ctx != NULL)
4170 return result;
4171}
4172
4173/** \test gid value too large. Related to bug #779 */
4174static int SigParseTest19 (void)
4175{
4176 int result = 0;
4177
4179 if (de_ctx == NULL)
4180 goto end;
4181
4182 if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; gid:99999999999999999999;)") != NULL)
4183 goto end;
4184
4185 result = 1;
4186end:
4187 if (de_ctx != NULL)
4189 return result;
4190}
4191
4192/** \test rev value too large. Related to bug #779 */
4193static int SigParseTest20 (void)
4194{
4195 int result = 0;
4196
4198 if (de_ctx == NULL)
4199 goto end;
4200
4201 if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; rev:99999999999999999999;)") != NULL)
4202 goto end;
4203
4204 result = 1;
4205end:
4206 if (de_ctx != NULL)
4208 return result;
4209}
4210
4211/** \test address parsing */
4212static int SigParseTest21 (void)
4213{
4214 int result = 0;
4215
4217 if (de_ctx == NULL)
4218 goto end;
4219
4220 if (DetectEngineAppendSig(de_ctx, "alert tcp [1.2.3.4, 1.2.3.5] any -> !1.2.3.4 any (sid:1;)") == NULL)
4221 goto end;
4222
4223 result = 1;
4224end:
4225 if (de_ctx != NULL)
4227 return result;
4228}
4229
4230/** \test address parsing */
4231static int SigParseTest22 (void)
4232{
4233 int result = 0;
4234
4236 if (de_ctx == NULL)
4237 goto end;
4238
4239 if (DetectEngineAppendSig(de_ctx, "alert tcp [10.10.10.0/24, !10.10.10.247] any -> [10.10.10.0/24, !10.10.10.247] any (sid:1;)") == NULL)
4240 goto end;
4241
4242 result = 1;
4243end:
4244 if (de_ctx != NULL)
4246 return result;
4247}
4248
4249/**
4250 * \test rule ending in carriage return
4251 */
4252static int SigParseTest23(void)
4253{
4256
4257 Signature *s = NULL;
4258
4259 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)\r");
4260 FAIL_IF_NULL(s);
4261
4263 PASS;
4264}
4265
4266/** \test Direction operator validation (invalid) */
4267static int SigParseBidirecTest06 (void)
4268{
4269 int result = 1;
4270 Signature *sig = NULL;
4271
4273 if (de_ctx == NULL)
4274 goto end;
4275
4276 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any - 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4277 if (sig == NULL)
4278 result = 1;
4279
4280end:
4281 if (sig != NULL) SigFree(de_ctx, sig);
4282 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4283 return result;
4284}
4285
4286/** \test Direction operator validation (invalid) */
4287static int SigParseBidirecTest07 (void)
4288{
4289 int result = 1;
4290 Signature *sig = NULL;
4291
4293 if (de_ctx == NULL)
4294 goto end;
4295
4296 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4297 if (sig == NULL)
4298 result = 1;
4299
4300end:
4301 if (sig != NULL) SigFree(de_ctx, sig);
4302 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4303 return result;
4304}
4305
4306/** \test Direction operator validation (invalid) */
4307static int SigParseBidirecTest08 (void)
4308{
4309 int result = 1;
4310 Signature *sig = NULL;
4311
4313 if (de_ctx == NULL)
4314 goto end;
4315
4316 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any < 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4317 if (sig == NULL)
4318 result = 1;
4319
4320end:
4321 if (sig != NULL) SigFree(de_ctx, sig);
4322 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4323 return result;
4324}
4325
4326/** \test Direction operator validation (invalid) */
4327static int SigParseBidirecTest09 (void)
4328{
4329 int result = 1;
4330 Signature *sig = NULL;
4331
4333 if (de_ctx == NULL)
4334 goto end;
4335
4336 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any > 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4337 if (sig == NULL)
4338 result = 1;
4339
4340end:
4341 if (sig != NULL) SigFree(de_ctx, sig);
4342 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4343 return result;
4344}
4345
4346/** \test Direction operator validation (invalid) */
4347static int SigParseBidirecTest10 (void)
4348{
4349 int result = 1;
4350 Signature *sig = NULL;
4351
4353 if (de_ctx == NULL)
4354 goto end;
4355
4356 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4357 if (sig == NULL)
4358 result = 1;
4359
4360end:
4361 if (sig != NULL) SigFree(de_ctx, sig);
4362 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4363 return result;
4364}
4365
4366/** \test Direction operator validation (invalid) */
4367static int SigParseBidirecTest11 (void)
4368{
4369 int result = 1;
4370 Signature *sig = NULL;
4371
4373 if (de_ctx == NULL)
4374 goto end;
4375
4376 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4377 if (sig == NULL)
4378 result = 1;
4379
4380end:
4381 if (sig != NULL) SigFree(de_ctx, sig);
4382 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4383 return result;
4384}
4385
4386/** \test Direction operator validation (invalid) */
4387static int SigParseBidirecTest12 (void)
4388{
4389 int result = 1;
4390 Signature *sig = NULL;
4391
4393 if (de_ctx == NULL)
4394 goto end;
4395
4396 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4397 if (sig == NULL)
4398 result = 1;
4399
4400end:
4401 if (sig != NULL) SigFree(de_ctx, sig);
4402 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4403 return result;
4404}
4405
4406/** \test Direction operator validation (valid) */
4407static int SigParseBidirecTest13 (void)
4408{
4409 int result = 1;
4410 Signature *sig = NULL;
4411
4413 if (de_ctx == NULL)
4414 goto end;
4415
4416 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4417 if (sig != NULL)
4418 result = 1;
4419
4420end:
4421 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4422 return result;
4423}
4424
4425/** \test Direction operator validation (valid) */
4426static int SigParseBidirecTest14 (void)
4427{
4428 int result = 1;
4429 Signature *sig = NULL;
4430
4432 if (de_ctx == NULL)
4433 goto end;
4434
4435 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4436 if (sig != NULL)
4437 result = 1;
4438
4439end:
4440 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4441 return result;
4442}
4443
4444/** \test Ensure that we don't set bidirectional in a
4445 * normal (one direction) Signature
4446 */
4447static int SigTestBidirec01 (void)
4448{
4449 Signature *sig = NULL;
4450 int result = 0;
4451
4453 if (de_ctx == NULL)
4454 goto end;
4455
4456 sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 -> !1.2.3.4 any (msg:\"SigTestBidirec01\"; sid:1;)");
4457 if (sig == NULL)
4458 goto end;
4459 if (sig->next != NULL)
4460 goto end;
4462 goto end;
4463 if (de_ctx->signum != 1)
4464 goto end;
4465
4466 result = 1;
4467
4468end:
4469 if (de_ctx != NULL) {
4473 }
4474 return result;
4475}
4476
4477/** \test Ensure that we set a bidirectional Signature correctly */
4478static int SigTestBidirec02 (void)
4479{
4480 int result = 0;
4481 Signature *sig = NULL;
4482 Signature *copy = NULL;
4483
4485 if (de_ctx == NULL)
4486 goto end;
4487
4488 de_ctx->flags |= DE_QUIET;
4489
4490 sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 <> !1.2.3.4 any (msg:\"SigTestBidirec02\"; sid:1;)");
4491 if (sig == NULL)
4492 goto end;
4493 if (de_ctx->sig_list != sig)
4494 goto end;
4496 goto end;
4497 if (sig->next == NULL)
4498 goto end;
4499 if (de_ctx->signum != 2)
4500 goto end;
4501 copy = sig->next;
4502 if (copy->next != NULL)
4503 goto end;
4505 goto end;
4506
4507 result = 1;
4508
4509end:
4510 if (de_ctx != NULL) {
4514 }
4515
4516 return result;
4517}
4518
4519/** \test Ensure that we set a bidirectional Signature correctly
4520* and we install it with the rest of the signatures, checking
4521* also that it match with the correct addr directions
4522*/
4523static int SigTestBidirec03 (void)
4524{
4525 int result = 0;
4526 Signature *sig = NULL;
4527 Packet *p = NULL;
4528
4530 if (de_ctx == NULL)
4531 goto end;
4532
4533 de_ctx->flags |= DE_QUIET;
4534
4535 const char *sigs[3];
4536 sigs[0] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)";
4537 sigs[1] = "alert tcp any any <> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)";
4538 sigs[2] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)";
4539 UTHAppendSigs(de_ctx, sigs, 3);
4540
4541 /* Checking that bidirectional rules are set correctly */
4542 sig = de_ctx->sig_list;
4543 if (sig == NULL)
4544 goto end;
4545 if (sig->next == NULL)
4546 goto end;
4547 if (sig->next->next == NULL)
4548 goto end;
4549 if (sig->next->next->next == NULL)
4550 goto end;
4551 if (sig->next->next->next->next != NULL)
4552 goto end;
4553 if (de_ctx->signum != 4)
4554 goto end;
4555
4556 uint8_t rawpkt1_ether[] = {
4557 0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
4558 0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
4559 0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
4560 0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
4561 0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
4562 0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
4563 0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
4564 0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
4565 0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
4566 0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
4567 0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
4568 0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
4569 0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
4570 0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
4571 0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
4572 0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
4573 0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
4574 0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
4575 0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
4576 0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
4577 0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
4578 0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
4579 0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
4580 0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
4581 0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
4582 0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
4583 0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
4584 0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
4585 0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
4586 0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
4587 0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
4588 0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
4589 0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
4590 0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
4591 0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4592 0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4593 0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
4594 0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
4595 0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
4596 0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
4597 0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
4598 0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
4599 0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
4600 0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4601 0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
4602 0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
4603 0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
4604 0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
4605 0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4606 0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
4607 0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
4608 0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
4609 0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
4610 0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
4611 0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */
4612
4614 p = UTHBuildPacketFromEth(rawpkt1_ether, sizeof(rawpkt1_ether));
4615 if (p == NULL) {
4616 SCLogDebug("Error building packet");
4617 goto end;
4618 }
4619 UTHMatchPackets(de_ctx, &p, 1);
4620
4621 uint32_t sids[3] = {1, 2, 3};
4622 uint32_t results[3] = {1, 1, 1};
4623 result = UTHCheckPacketMatchResults(p, sids, results, 1);
4624
4625end:
4626 if (p != NULL) {
4627 PacketRecycle(p);
4628 SCFree(p);
4629 }
4630 FlowShutdown();
4631 return result;
4632}
4633
4634/** \test Ensure that we set a bidirectional Signature correctly
4635* and we install it with the rest of the signatures, checking
4636* also that it match with the correct addr directions
4637*/
4638static int SigTestBidirec04 (void)
4639{
4640 int result = 0;
4641 Signature *sig = NULL;
4642 Packet *p = NULL;
4643
4645 if (de_ctx == NULL)
4646 goto end;
4647
4648 de_ctx->flags |= DE_QUIET;
4649
4650 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)");
4651 if (sig == NULL)
4652 goto end;
4653 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> any any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)");
4654 if (sig == NULL)
4655 goto end;
4657 goto end;
4658 if (sig->next == NULL)
4659 goto end;
4660 if (sig->next->next == NULL)
4661 goto end;
4662 if (sig->next->next->next != NULL)
4663 goto end;
4664 if (de_ctx->signum != 3)
4665 goto end;
4666
4667 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)");
4668 if (sig == NULL)
4669 goto end;
4670 if (sig->next == NULL)
4671 goto end;
4672 if (sig->next->next == NULL)
4673 goto end;
4674 if (sig->next->next->next == NULL)
4675 goto end;
4676 if (sig->next->next->next->next != NULL)
4677 goto end;
4678 if (de_ctx->signum != 4)
4679 goto end;
4680
4681 uint8_t rawpkt1_ether[] = {
4682 0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
4683 0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
4684 0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
4685 0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
4686 0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
4687 0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
4688 0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
4689 0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
4690 0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
4691 0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
4692 0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
4693 0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
4694 0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
4695 0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
4696 0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
4697 0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
4698 0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
4699 0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
4700 0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
4701 0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
4702 0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
4703 0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
4704 0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
4705 0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
4706 0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
4707 0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
4708 0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
4709 0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
4710 0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
4711 0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
4712 0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
4713 0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
4714 0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
4715 0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
4716 0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4717 0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4718 0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
4719 0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
4720 0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
4721 0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
4722 0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
4723 0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
4724 0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
4725 0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4726 0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
4727 0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
4728 0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
4729 0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
4730 0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4731 0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
4732 0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
4733 0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
4734 0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
4735 0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
4736 0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */
4737
4738 p = PacketGetFromAlloc();
4739 if (unlikely(p == NULL))
4740 return 0;
4742 ThreadVars th_v;
4743 DetectEngineThreadCtx *det_ctx;
4744
4745 memset(&th_v, 0, sizeof(th_v));
4746
4748 DecodeEthernet(&th_v, &dtv, p, rawpkt1_ether, sizeof(rawpkt1_ether));
4749 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
4750
4751 /* At this point we have a list of 4 signatures. The last one
4752 is a copy of the second one. If we receive a packet
4753 with source 192.168.1.1 80, all the sids should match */
4754
4756 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4757
4758 /* only sid 2 should match with a packet going to 192.168.1.1 port 80 */
4759 if (PacketAlertCheck(p, 1) <= 0 && PacketAlertCheck(p, 3) <= 0 &&
4760 PacketAlertCheck(p, 2) == 1) {
4761 result = 1;
4762 }
4763
4764 if (p != NULL) {
4765 PacketRecycle(p);
4766 }
4767 FlowShutdown();
4768 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
4769
4770end:
4771 if (de_ctx != NULL) {
4775 }
4776
4777 if (p != NULL)
4778 SCFree(p);
4779 return result;
4780}
4781
4782/**
4783 * \test check that we don't allow invalid negation options
4784 */
4785static int SigParseTestNegation01 (void)
4786{
4789 de_ctx->flags |= DE_QUIET;
4790 Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp !any any -> any any (sid:1;)");
4793 PASS;
4794}
4795
4796/**
4797 * \test check that we don't allow invalid negation options
4798 */
4799static int SigParseTestNegation02 (void)
4800{
4801 int result = 0;
4803 Signature *s=NULL;
4804
4806 if (de_ctx == NULL)
4807 goto end;
4808 de_ctx->flags |= DE_QUIET;
4809
4810 s = SigInit(de_ctx,"alert tcp any !any -> any any (msg:\"SigTest41-02 src ip is !any \"; classtype:misc-activity; sid:410002; rev:1;)");
4811 if (s != NULL) {
4812 SigFree(de_ctx, s);
4813 goto end;
4814 }
4815
4816 result = 1;
4817end:
4818 if (de_ctx != NULL)
4820 return result;
4821}
4822/**
4823 * \test check that we don't allow invalid negation options
4824 */
4825static int SigParseTestNegation03 (void)
4826{
4827 int result = 0;
4829 Signature *s=NULL;
4830
4832 if (de_ctx == NULL)
4833 goto end;
4834 de_ctx->flags |= DE_QUIET;
4835
4836 s = SigInit(de_ctx,"alert tcp any any -> any [80:!80] (msg:\"SigTest41-03 dst port [80:!80] \"; classtype:misc-activity; sid:410003; rev:1;)");
4837 if (s != NULL) {
4838 SigFree(de_ctx, s);
4839 goto end;
4840 }
4841
4842 result = 1;
4843end:
4844 if (de_ctx != NULL)
4846 return result;
4847}
4848/**
4849 * \test check that we don't allow invalid negation options
4850 */
4851static int SigParseTestNegation04 (void)
4852{
4853 int result = 0;
4855 Signature *s=NULL;
4856
4858 if (de_ctx == NULL)
4859 goto end;
4860 de_ctx->flags |= DE_QUIET;
4861
4862 s = SigInit(de_ctx,"alert tcp any any -> any [80,!80] (msg:\"SigTest41-03 dst port [80:!80] \"; classtype:misc-activity; sid:410003; rev:1;)");
4863 if (s != NULL) {
4864 SigFree(de_ctx, s);
4865 goto end;
4866 }
4867
4868 result = 1;
4869end:
4870 if (de_ctx != NULL)
4872 return result;
4873}
4874/**
4875 * \test check that we don't allow invalid negation options
4876 */
4877static int SigParseTestNegation05 (void)
4878{
4879 int result = 0;
4881 Signature *s=NULL;
4882
4884 if (de_ctx == NULL)
4885 goto end;
4886 de_ctx->flags |= DE_QUIET;
4887
4888 s = SigInit(de_ctx,"alert tcp any any -> [192.168.0.2,!192.168.0.2] any (msg:\"SigTest41-04 dst ip [192.168.0.2,!192.168.0.2] \"; classtype:misc-activity; sid:410004; rev:1;)");
4889 if (s != NULL) {
4890 SigFree(de_ctx, s);
4891 goto end;
4892 }
4893
4894 result = 1;
4895end:
4896 if (de_ctx != NULL)
4898 return result;
4899}
4900/**
4901 * \test check that we don't allow invalid negation options
4902 */
4903static int SigParseTestNegation06 (void)
4904{
4905 int result = 0;
4907 Signature *s=NULL;
4908
4910 if (de_ctx == NULL)
4911 goto end;
4912 de_ctx->flags |= DE_QUIET;
4913
4914 s = SigInit(de_ctx,"alert tcp any any -> any [100:1000,!1:20000] (msg:\"SigTest41-05 dst port [100:1000,!1:20000] \"; classtype:misc-activity; sid:410005; rev:1;)");
4915 if (s != NULL) {
4916 SigFree(de_ctx, s);
4917 goto end;
4918 }
4919
4920 result = 1;
4921end:
4922 if (de_ctx != NULL)
4924 return result;
4925}
4926
4927/**
4928 * \test check that we don't allow invalid negation options
4929 */
4930static int SigParseTestNegation07 (void)
4931{
4934 de_ctx->flags |= DE_QUIET;
4936 de_ctx, "alert tcp any any -> [192.168.0.2,!192.168.0.0/24] any (sid:410006;)");
4939 PASS;
4940}
4941
4942/**
4943 * \test check valid negation bug 1079
4944 */
4945static int SigParseTestNegation08 (void)
4946{
4947 int result = 0;
4949 Signature *s=NULL;
4950
4952 if (de_ctx == NULL)
4953 goto end;
4954 de_ctx->flags |= DE_QUIET;
4955
4956 s = SigInit(de_ctx,"alert tcp any any -> [192.168.0.0/16,!192.168.0.0/24] any (sid:410006; rev:1;)");
4957 if (s == NULL) {
4958 goto end;
4959 }
4960
4961 result = 1;
4962end:
4963 if (de_ctx != NULL)
4965 return result;
4966}
4967
4968/**
4969 * \test mpm
4970 */
4971static int SigParseTestMpm01 (void)
4972{
4973 int result = 0;
4974 Signature *sig = NULL;
4975
4977 if (de_ctx == NULL)
4978 goto end;
4979
4980 sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; sid:1;)");
4981 if (sig == NULL) {
4982 printf("sig failed to init: ");
4983 goto end;
4984 }
4985
4986 if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
4987 printf("sig doesn't have content list: ");
4988 goto end;
4989 }
4990
4991 result = 1;
4992end:
4993 if (sig != NULL)
4994 SigFree(de_ctx, sig);
4996 return result;
4997}
4998
4999/**
5000 * \test mpm
5001 */
5002static int SigParseTestMpm02 (void)
5003{
5004 int result = 0;
5005 Signature *sig = NULL;
5006
5008 if (de_ctx == NULL)
5009 goto end;
5010
5011 sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; content:\"abcdef\"; sid:1;)");
5012 if (sig == NULL) {
5013 printf("sig failed to init: ");
5014 goto end;
5015 }
5016
5017 if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
5018 printf("sig doesn't have content list: ");
5019 goto end;
5020 }
5021
5022 result = 1;
5023end:
5024 if (sig != NULL)
5025 SigFree(de_ctx, sig);
5027 return result;
5028}
5029
5030/**
5031 * \test test tls (app layer) rule
5032 */
5033static int SigParseTestAppLayerTLS01(void)
5034{
5035 int result = 0;
5037 Signature *s=NULL;
5038
5040 if (de_ctx == NULL)
5041 goto end;
5042 de_ctx->flags |= DE_QUIET;
5043
5044 s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS01 \"; sid:410006; rev:1;)");
5045 if (s == NULL) {
5046 printf("parsing sig failed: ");
5047 goto end;
5048 }
5049
5050 if (s->alproto == 0) {
5051 printf("alproto not set: ");
5052 goto end;
5053 }
5054
5055 result = 1;
5056end:
5057 if (s != NULL)
5058 SigFree(de_ctx, s);
5059 if (de_ctx != NULL)
5061
5062 return result;
5063}
5064
5065/**
5066 * \test test tls (app layer) rule
5067 */
5068static int SigParseTestAppLayerTLS02(void)
5069{
5070 int result = 0;
5072 Signature *s=NULL;
5073
5075 if (de_ctx == NULL)
5076 goto end;
5077 de_ctx->flags |= DE_QUIET;
5078
5079 s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS02 \"; tls.version:1.0; sid:410006; rev:1;)");
5080 if (s == NULL) {
5081 printf("parsing sig failed: ");
5082 goto end;
5083 }
5084
5085 if (s->alproto == 0) {
5086 printf("alproto not set: ");
5087 goto end;
5088 }
5089
5090 result = 1;
5091end:
5092 if (s != NULL)
5093 SigFree(de_ctx, s);
5094 if (de_ctx != NULL)
5096 return result;
5097}
5098
5099/**
5100 * \test test tls (app layer) rule
5101 */
5102static int SigParseTestAppLayerTLS03(void)
5103{
5104 int result = 0;
5106 Signature *s=NULL;
5107
5109 if (de_ctx == NULL)
5110 goto end;
5111 de_ctx->flags |= DE_QUIET;
5112
5113 s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS03 \"; tls.version:2.5; sid:410006; rev:1;)");
5114 if (s != NULL) {
5115 SigFree(de_ctx, s);
5116 goto end;
5117 }
5118
5119 result = 1;
5120end:
5121 if (de_ctx != NULL)
5123 return result;
5124}
5125
5126static int SigParseTestUnbalancedQuotes01(void)
5127{
5129 Signature *s;
5130
5133 de_ctx->flags |= DE_QUIET;
5134
5135 s = SigInit(de_ctx,
5136 "alert http any any -> any any (msg:\"SigParseTestUnbalancedQuotes01\"; "
5137 "pcre:\"/\\/[a-z]+\\.php\\?[a-z]+?=\\d{7}&[a-z]+?=\\d{7,8}$/U\" "
5138 "flowbits:set,et.exploitkitlanding; classtype:trojan-activity; sid:2017078; rev:5;)");
5140
5141 PASS;
5142}
5143
5144static int SigParseTestContentGtDsize01(void)
5145{
5148 de_ctx->flags |= DE_QUIET;
5149
5151 "alert http any any -> any any ("
5152 "dsize:21; content:\"0123456789001234567890|00 00|\"; "
5153 "sid:1; rev:1;)");
5155
5156 PASS;
5157}
5158
5159static int SigParseTestContentGtDsize02(void)
5160{
5163 de_ctx->flags |= DE_QUIET;
5164
5166 "alert http any any -> any any ("
5167 "dsize:21; content:\"0123456789|00 00|\"; offset:10; "
5168 "sid:1; rev:1;)");
5170
5171 PASS;
5172}
5173
5174static int CountSigsWithSid(const DetectEngineCtx *de_ctx, const uint32_t sid)
5175{
5176 int cnt = 0;
5177 for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
5178 if (sid == s->id)
5179 cnt++;
5180 }
5181 return cnt;
5182}
5183
5184static int SigParseBidirWithSameSrcAndDest01(void)
5185{
5188 de_ctx->flags |= DE_QUIET;
5189
5190 Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any <> any any (sid:1;)");
5191 FAIL_IF_NULL(s);
5192 FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 1);
5194
5195 s = DetectEngineAppendSig(de_ctx, "alert tcp any [80, 81] <> any [81, 80] (sid:2;)");
5196 FAIL_IF_NULL(s);
5197 FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 1);
5199
5201 "alert tcp [1.2.3.4, 5.6.7.8] [80, 81] <> [5.6.7.8, 1.2.3.4] [81, 80] (sid:3;)");
5202 FAIL_IF_NULL(s);
5203 FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 1);
5205
5207 PASS;
5208}
5209
5210static int SigParseBidirWithSameSrcAndDest02(void)
5211{
5214 de_ctx->flags |= DE_QUIET;
5215
5216 // Source is a subset of destination
5218 de_ctx, "alert tcp 1.2.3.4 any <> [1.2.3.4, 5.6.7.8, ::1] any (sid:1;)");
5219 FAIL_IF_NULL(s);
5220 FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 2);
5222
5223 // Source is a subset of destination
5225 de_ctx, "alert tcp [1.2.3.4, ::1] [80, 81, 82] <> [1.2.3.4, ::1] [80, 81] (sid:2;)");
5226 FAIL_IF_NULL(s);
5227 FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 2);
5229
5230 // Source intersects with destination
5232 "alert tcp [1.2.3.4, ::1, ABCD:AAAA::1] [80] <> [1.2.3.4, ::1] [80, 81] (sid:3;)");
5233 FAIL_IF_NULL(s);
5234 FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 2);
5236
5237 // mix in negation, these are the same
5239 de_ctx, "alert tcp [!1.2.3.4, 1.2.3.0/24] any <> [1.2.3.0/24, !1.2.3.4] any (sid:4;)");
5240 FAIL_IF_NULL(s);
5241 FAIL_IF_NOT(CountSigsWithSid(de_ctx, 4) == 1);
5243
5244 // mix in negation, these are not the same
5246 de_ctx, "alert tcp [1.2.3.4, 1.2.3.0/24] any <> [1.2.3.0/24, !1.2.3.4] any (sid:5;)");
5247 FAIL_IF_NULL(s);
5248 FAIL_IF_NOT(CountSigsWithSid(de_ctx, 5) == 2);
5250
5252 PASS;
5253}
5254
5255static int SigParseTestActionReject(void)
5256{
5259
5261 de_ctx, "reject tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
5262#ifdef HAVE_LIBNET11
5263 FAIL_IF_NULL(sig);
5265#else
5266 FAIL_IF_NOT_NULL(sig);
5267#endif
5268
5270 PASS;
5271}
5272
5273static int SigParseTestActionDrop(void)
5274{
5277
5279 de_ctx, "drop tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
5280 FAIL_IF_NULL(sig);
5282
5284 PASS;
5285}
5286
5287static int SigSetMultiAppProto(void)
5288{
5289 Signature *s = SigAlloc();
5290 FAIL_IF_NULL(s);
5291
5292 AppProto alprotos[] = { 1, 2, 3, ALPROTO_UNKNOWN };
5293 FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5294
5295 // check intersection gives multiple entries
5296 alprotos[0] = 3;
5297 alprotos[1] = 2;
5298 alprotos[2] = ALPROTO_UNKNOWN;
5299 FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5300 FAIL_IF(s->init_data->alprotos[0] != 3);
5301 FAIL_IF(s->init_data->alprotos[1] != 2);
5303
5304 // check single after multiple
5307 FAIL_IF(s->alproto != 3);
5308 alprotos[0] = 4;
5309 alprotos[1] = 3;
5310 alprotos[2] = ALPROTO_UNKNOWN;
5311 // check multiple containing singleton
5312 FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5313 FAIL_IF(s->alproto != 3);
5314
5315 // reset
5317 alprotos[0] = 1;
5318 alprotos[1] = 2;
5319 alprotos[2] = 3;
5320 alprotos[3] = ALPROTO_UNKNOWN;
5321 FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5322 // fail if set single not in multiple
5324
5327 alprotos[0] = 1;
5328 alprotos[1] = 2;
5329 alprotos[2] = 3;
5330 alprotos[3] = ALPROTO_UNKNOWN;
5331 FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5332 alprotos[0] = 4;
5333 alprotos[1] = 5;
5334 alprotos[2] = ALPROTO_UNKNOWN;
5335 // fail if multiple do not have intersection
5336 FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
5337
5340 alprotos[0] = 1;
5341 alprotos[1] = 2;
5342 alprotos[2] = 3;
5343 alprotos[3] = ALPROTO_UNKNOWN;
5344 FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5345 alprotos[0] = 3;
5346 alprotos[1] = 4;
5347 alprotos[2] = 5;
5348 alprotos[3] = ALPROTO_UNKNOWN;
5349 // check multiple intersect to singleton
5350 FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5351 FAIL_IF(s->alproto != 3);
5352 alprotos[0] = 5;
5353 alprotos[1] = 4;
5354 alprotos[2] = ALPROTO_UNKNOWN;
5355 // fail if multiple do not belong to singleton
5356 FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
5357
5358 SigFree(NULL, s);
5359 PASS;
5360}
5361
5362static int DetectSetupDirection01(void)
5363{
5364 Signature *s = SigAlloc();
5365 FAIL_IF_NULL(s);
5366 // Basic case : ok
5367 char *str = (char *)"to_client";
5368 FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
5369 SigFree(NULL, s);
5370 PASS;
5371}
5372
5373static int DetectSetupDirection02(void)
5374{
5375 Signature *s = SigAlloc();
5376 FAIL_IF_NULL(s);
5377 char *str = (char *)"to_server";
5378 FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
5379 // ok so far
5380 str = (char *)"to_client";
5381 FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5382 // fails because we cannot have both to_client and to_server for same signature
5383 SigFree(NULL, s);
5384 PASS;
5385}
5386
5387static int DetectSetupDirection03(void)
5388{
5389 Signature *s = SigAlloc();
5390 FAIL_IF_NULL(s);
5391 char *str = (char *)"to_client , something";
5392 FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5393 FAIL_IF(strcmp(str, "something") != 0);
5394 str = (char *)"to_client,something";
5395 FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5396 FAIL_IF(strcmp(str, "something") != 0);
5397 SigFree(NULL, s);
5398 PASS;
5399}
5400
5401static int DetectSetupDirection04(void)
5402{
5403 Signature *s = SigAlloc();
5404 FAIL_IF_NULL(s);
5405 // invalid case
5406 char *str = (char *)"to_client_toto";
5407 FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5408 // test we do not change the string pointer if only_dir is false
5409 str = (char *)"to_client_toto";
5410 FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5411 FAIL_IF(strcmp(str, "to_client_toto") != 0);
5412 str = (char *)"to_client,something";
5413 // fails because we call with only_dir=true
5414 FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5415 SigFree(NULL, s);
5416 PASS;
5417}
5418
5419#endif /* UNITTESTS */
5420
5421#ifdef UNITTESTS
5422void DetectParseRegisterTests (void);
5423#include "tests/detect-parse.c"
5424#endif
5425
5427{
5428#ifdef UNITTESTS
5430
5431 UtRegisterTest("SigParseTest01", SigParseTest01);
5432 UtRegisterTest("SigParseTest02", SigParseTest02);
5433 UtRegisterTest("SigParseTest03", SigParseTest03);
5434 UtRegisterTest("SigParseTest04", SigParseTest04);
5435 UtRegisterTest("SigParseTest05", SigParseTest05);
5436 UtRegisterTest("SigParseTest06", SigParseTest06);
5437 UtRegisterTest("SigParseTest07", SigParseTest07);
5438 UtRegisterTest("SigParseTest08", SigParseTest08);
5439 UtRegisterTest("SigParseTest09", SigParseTest09);
5440 UtRegisterTest("SigParseTest10", SigParseTest10);
5441 UtRegisterTest("SigParseTest11", SigParseTest11);
5442 UtRegisterTest("SigParseTest12", SigParseTest12);
5443 UtRegisterTest("SigParseTest13", SigParseTest13);
5444 UtRegisterTest("SigParseTest14", SigParseTest14);
5445 UtRegisterTest("SigParseTest15", SigParseTest15);
5446 UtRegisterTest("SigParseTest16", SigParseTest16);
5447 UtRegisterTest("SigParseTest17", SigParseTest17);
5448 UtRegisterTest("SigParseTest18", SigParseTest18);
5449 UtRegisterTest("SigParseTest19", SigParseTest19);
5450 UtRegisterTest("SigParseTest20", SigParseTest20);
5451 UtRegisterTest("SigParseTest21 -- address with space", SigParseTest21);
5452 UtRegisterTest("SigParseTest22 -- address with space", SigParseTest22);
5453 UtRegisterTest("SigParseTest23 -- carriage return", SigParseTest23);
5454
5455 UtRegisterTest("SigParseBidirecTest06", SigParseBidirecTest06);
5456 UtRegisterTest("SigParseBidirecTest07", SigParseBidirecTest07);
5457 UtRegisterTest("SigParseBidirecTest08", SigParseBidirecTest08);
5458 UtRegisterTest("SigParseBidirecTest09", SigParseBidirecTest09);
5459 UtRegisterTest("SigParseBidirecTest10", SigParseBidirecTest10);
5460 UtRegisterTest("SigParseBidirecTest11", SigParseBidirecTest11);
5461 UtRegisterTest("SigParseBidirecTest12", SigParseBidirecTest12);
5462 UtRegisterTest("SigParseBidirecTest13", SigParseBidirecTest13);
5463 UtRegisterTest("SigParseBidirecTest14", SigParseBidirecTest14);
5464 UtRegisterTest("SigTestBidirec01", SigTestBidirec01);
5465 UtRegisterTest("SigTestBidirec02", SigTestBidirec02);
5466 UtRegisterTest("SigTestBidirec03", SigTestBidirec03);
5467 UtRegisterTest("SigTestBidirec04", SigTestBidirec04);
5468 UtRegisterTest("SigParseTestNegation01", SigParseTestNegation01);
5469 UtRegisterTest("SigParseTestNegation02", SigParseTestNegation02);
5470 UtRegisterTest("SigParseTestNegation03", SigParseTestNegation03);
5471 UtRegisterTest("SigParseTestNegation04", SigParseTestNegation04);
5472 UtRegisterTest("SigParseTestNegation05", SigParseTestNegation05);
5473 UtRegisterTest("SigParseTestNegation06", SigParseTestNegation06);
5474 UtRegisterTest("SigParseTestNegation07", SigParseTestNegation07);
5475 UtRegisterTest("SigParseTestNegation08", SigParseTestNegation08);
5476 UtRegisterTest("SigParseTestMpm01", SigParseTestMpm01);
5477 UtRegisterTest("SigParseTestMpm02", SigParseTestMpm02);
5478 UtRegisterTest("SigParseTestAppLayerTLS01", SigParseTestAppLayerTLS01);
5479 UtRegisterTest("SigParseTestAppLayerTLS02", SigParseTestAppLayerTLS02);
5480 UtRegisterTest("SigParseTestAppLayerTLS03", SigParseTestAppLayerTLS03);
5481 UtRegisterTest("SigParseTestUnbalancedQuotes01", SigParseTestUnbalancedQuotes01);
5482
5483 UtRegisterTest("SigParseTestContentGtDsize01",
5484 SigParseTestContentGtDsize01);
5485 UtRegisterTest("SigParseTestContentGtDsize02",
5486 SigParseTestContentGtDsize02);
5487
5488 UtRegisterTest("SigParseBidirWithSameSrcAndDest01",
5489 SigParseBidirWithSameSrcAndDest01);
5490 UtRegisterTest("SigParseBidirWithSameSrcAndDest02",
5491 SigParseBidirWithSameSrcAndDest02);
5492 UtRegisterTest("SigParseTestActionReject", SigParseTestActionReject);
5493 UtRegisterTest("SigParseTestActionDrop", SigParseTestActionDrop);
5494
5495 UtRegisterTest("SigSetMultiAppProto", SigSetMultiAppProto);
5496
5497 UtRegisterTest("DetectSetupDirection01", DetectSetupDirection01);
5498 UtRegisterTest("DetectSetupDirection02", DetectSetupDirection02);
5499 UtRegisterTest("DetectSetupDirection03", DetectSetupDirection03);
5500 UtRegisterTest("DetectSetupDirection04", DetectSetupDirection04);
5501
5502#endif /* UNITTESTS */
5503}
#define ACTION_REJECT
#define ACTION_PASS
#define ACTION_ACCEPT
#define ACTION_REJECT_BOTH
#define ACTION_REJECT_DST
@ ACTION_SCOPE_HOOK
@ ACTION_SCOPE_PACKET
@ ACTION_SCOPE_TX
@ ACTION_SCOPE_FLOW
#define ACTION_CONFIG
#define ACTION_ALERT
#define ACTION_DROP
void AppLayerProtoDetectSupportedIpprotos(AppProto alproto, uint8_t *ipprotos)
const char * AppLayerProtoDetectGetProtoName(AppProto alproto)
uint8_t len
uint16_t dst
uint16_t src
struct HtpBodyChunk_ * next
int AppLayerParserGetStateProgressCompletionStatus(AppProto alproto, uint8_t direction)
int AppLayerParserGetStateIdByName(uint8_t ipproto, AppProto alproto, const char *name, const uint8_t direction)
bool AppLayerParserSupportsFiles(uint8_t ipproto, AppProto alproto)
const char * AppLayerParserGetStateNameById(uint8_t ipproto, AppProto alproto, const int id, const uint8_t direction)
AppProto g_alproto_max
const char * AppProtoToString(AppProto alproto)
Maps the ALPROTO_*, to its string equivalent.
uint16_t AppProto
@ ALPROTO_HTTP2
@ ALPROTO_FAILED
@ ALPROTO_HTTP
@ ALPROTO_UNKNOWN
@ ALPROTO_HTTP1
AppProto AppLayerGetProtoByName(const char *alproto_name)
Given a protocol string, returns the corresponding internal protocol id.
Definition app-layer.c:1002
int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
uint8_t flags
Definition decode-gre.h:0
uint8_t proto
uint16_t type
bool DetectBsizeValidateContentCallback(const Signature *s, const SignatureInitDataBuffer *b)
bool DetectContentPMATCHValidateCallback(const Signature *s)
#define DETECT_CONTENT_DEPTH
#define DETECT_CONTENT_RELATIVE_NEXT
#define DETECT_CONTENT_RAWBYTES
#define DETECT_CONTENT_WITHIN
#define DETECT_CONTENT_DISTANCE
#define DETECT_CONTENT_OFFSET
#define DETECT_CONTENT_REPLACE
const DetectAddressHead * DetectParseAddress(DetectEngineCtx *de_ctx, const char *string, bool *contains_negation)
bool DetectAddressListsAreEqual(DetectAddress *list1, DetectAddress *list2)
Checks if two address group lists are equal.
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
void SigCleanSignatures(DetectEngineCtx *de_ctx)
int SigGroupCleanup(DetectEngineCtx *de_ctx)
void SignatureSetType(DetectEngineCtx *de_ctx, Signature *s)
int IPOnlySigParseAddress(const DetectEngineCtx *de_ctx, Signature *s, const char *addrstr, char flag)
Parses an address group sent as a character string and updates the IPOnlyCIDRItem lists src and dst o...
void IPOnlyCIDRListFree(IPOnlyCIDRItem *tmphead)
This function free a IPOnlyCIDRItem list.
void RetrieveFPForSig(const DetectEngineCtx *de_ctx, Signature *s)
int DetectPortParse(const DetectEngineCtx *de_ctx, DetectPort **head, const char *str)
Function for parsing port strings.
void DetectPortPrint(DetectPort *dp)
Helper function that print the DetectPort info.
void DetectPortCleanupList(const DetectEngineCtx *de_ctx, DetectPort *head)
Free a DetectPort list and each of its members.
bool DetectPortListsAreEqual(DetectPort *list1, DetectPort *list2)
Checks if two port group lists are equal.
int DetectPortCmp(DetectPort *a, DetectPort *b)
Function that compare port groups.
int DetectProtoParse(DetectProto *dp, const char *str)
Parses a protocol sent as a string.
#define DETECT_PROTO_ONLY_PKT
#define DETECT_PROTO_ONLY_STREAM
#define DETECT_PROTO_ANY
int DETECT_TBLSIZE
@ DETECT_STREAM_SIZE
DetectEngineCtx * DetectEngineCtxInit(void)
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Data structures and function prototypes for keeping state for the detection engine.
bool DetectEngineBufferRunValidateCallback(const DetectEngineCtx *de_ctx, const int id, const Signature *s, const char **sigerror)
const char * DetectEngineBufferTypeGetNameById(const DetectEngineCtx *de_ctx, const int id)
void DetectEngineBufferRunSetupCallback(const DetectEngineCtx *de_ctx, const int id, Signature *s)
void DetectEngineAppInspectionEngineSignatureFree(DetectEngineCtx *de_ctx, Signature *s)
free app inspect engines for a signature
const char * DetectTableToString(enum DetectTable table)
void DetectAppLayerInspectEngineRegister(const char *name, AppProto alproto, uint32_t dir, int progress, InspectEngineFuncPtr Callback, InspectionBufferGetDataPtr GetData)
Registers an app inspection engine.
const DetectBufferType * DetectEngineBufferTypeGetById(const DetectEngineCtx *de_ctx, const int id)
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
bool DetectEngineBufferTypeSupportsMpmGetById(const DetectEngineCtx *de_ctx, const int id)
int DetectBufferTypeGetByName(const char *name)
uint8_t DetectEngineInspectGenericList(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
Do the content inspection & validation for a signature.
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
int DetectFlowSetupImplicit(Signature *s, uint32_t flags)
uint32_t id
void DetectIPProtoRemoveAllSMs(DetectEngineCtx *de_ctx, Signature *s)
bool DetectAbsentValidateContentCallback(const Signature *s, const SignatureInitDataBuffer *b)
void DetectMetadataFree(DetectMetadata *mdata)
Free a Metadata object.
#define CASE_CODE_STRING(E, S)
int SignatureInitDataBufferCheckExpand(Signature *s)
check if buffers array still has space left, expand if not
void DetectParseDupSigHashFree(DetectEngineCtx *de_ctx)
Frees the hash table that is used to cull duplicate sigs.
SigMatch * DetectGetLastSMFromMpmLists(const DetectEngineCtx *de_ctx, const Signature *s)
get the last SigMatch from lists that support MPM.
void DetectRegisterAppLayerHookLists(void)
register app hooks as generic lists
SigMatch * DetectGetLastSMByListId(const Signature *s, int list_id,...)
Returns the sm with the largest index (added last) from the list passed to us as an id.
struct SigDuplWrapper_ SigDuplWrapper
Registration table for file handlers.
bool SigMatchStrictEnabled(const enum DetectKeywordId id)
void DetectParseRegexAddToFreeList(DetectParseRegex *detect_parse)
add regex and/or study to at exit free list
DetectParseRegex * DetectSetupPCRE2(const char *parse_str, int opts)
SigMatch * DetectGetLastSMByListPtr(const Signature *s, SigMatch *sm_list,...)
Returns the sm with the largest index (added last) from the list passed to us as a pointer.
void DetectParseFreeRegex(DetectParseRegex *r)
int SC_Pcre2SubstringGet(pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR **bufferptr, PCRE2_SIZE *bufflen)
void DetectParseFreeRegexes(void)
#define URL
void DetectParseRegisterTests(void)
this function registers unit tests for DetectParse
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
SigMatchData * SigMatchList2DataArray(SigMatch *head)
convert SigMatch list to SigMatchData array
#define CASE_CODE(E)
const char * DetectListToHumanString(int list)
const char * DetectListToString(int list)
int SCDetectSignatureSetAppProto(Signature *s, AppProto alproto)
void SigTableApplyStrictCommandLineOption(const char *str)
int g_skip_prefilter
struct SignatureParser_ SignatureParser
SigMatch * SigMatchAlloc(void)
void SigFree(DetectEngineCtx *de_ctx, Signature *s)
int DetectParseDupSigHashInit(DetectEngineCtx *de_ctx)
Initializes the hash table that is used to cull duplicate sigs.
int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str, int start_offset, int options)
int DetectSignatureSetMultiAppProto(Signature *s, const AppProto *alprotos)
this function is used to set multiple possible app-layer protos
int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg, int sm_type, int sm_list, AppProto alproto)
void SigParseRegisterTests(void)
int SC_Pcre2SubstringCopy(pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR *buffer, PCRE2_SIZE *bufflen)
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
SigMatch * SCSigMatchAppendSMToList(DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
Append a SigMatch to the list type.
Signature * DetectFirewallRuleAppendNew(DetectEngineCtx *de_ctx, const char *sigstr)
Parse and append a Signature into the Detection Engine Context signature list.
SigMatch * DetectGetLastSMFromLists(const Signature *s,...)
Returns the sm with the largest index (added latest) from the lists passed to us.
Signature * SigAlloc(void)
bool sc_set_caps
Definition suricata.c:189
bool SigMatchSilentErrorEnabled(const DetectEngineCtx *de_ctx, const enum DetectKeywordId id)
int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm)
void SigMatchRemoveSMFromList(Signature *s, SigMatch *sm, int sm_list)
SigMatch * DetectGetLastSM(const Signature *s)
Returns the sm with the largest index (added latest) from this sig.
bool DetectSetupParseRegexesOpts(const char *parse_str, DetectParseRegex *detect_parse, int opts)
SigTableElmt * sigmatch_table
Signature * DetectEngineAppendSig(DetectEngineCtx *de_ctx, const char *sigstr)
Parse and append a Signature into the Detection Engine Context signature list.
void SigMatchFree(DetectEngineCtx *de_ctx, SigMatch *sm)
free a SigMatch
@ SIG_DIREC_DST
@ SIG_DIREC_SRC
@ SIG_DIREC_SWITCHED
@ SIG_DIREC_NORMAL
#define DETECT_PCRE_RELATIVE_NEXT
Definition detect-pcre.h:34
#define SC_MATCH_LIMIT_RECURSION_DEFAULT
Definition detect-pcre.h:44
#define SC_MATCH_LIMIT_DEFAULT
Definition detect-pcre.h:43
void DetectReferenceFree(DetectReference *ref)
Free a Reference object.
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition detect.c:2420
#define SIG_FLAG_FILESTORE
Definition detect.h:269
#define SIGMATCH_SUPPORT_DIR
Definition detect.h:1684
#define SIG_FLAG_INIT_FORCE_TOSERVER
Definition detect.h:302
#define FILE_SIG_NEED_FILENAME
Definition detect.h:321
SignatureHookPkt
Definition detect.h:538
@ SIGNATURE_HOOK_PKT_NOT_SET
Definition detect.h:539
@ SIGNATURE_HOOK_PKT_PRE_STREAM
Definition detect.h:542
@ SIGNATURE_HOOK_PKT_ALL
Definition detect.h:543
@ SIGNATURE_HOOK_PKT_PRE_FLOW
Definition detect.h:541
@ SIGNATURE_HOOK_PKT_FLOW_START
Definition detect.h:540
#define SIG_ALPROTO_MAX
Definition detect.h:587
#define SIGMATCH_NOOPT
Definition detect.h:1651
#define DE_QUIET
Definition detect.h:330
#define DETECT_SM_LIST_NOTSET
Definition detect.h:144
#define SIG_FLAG_SP_ANY
Definition detect.h:243
@ DETECT_PREFILTER_AUTO
Definition detect.h:897
#define SIG_FLAG_REQUIRE_PACKET
Definition detect.h:254
#define SIG_FLAG_TOCLIENT
Definition detect.h:272
#define SIGMATCH_SUPPORT_FIREWALL
Definition detect.h:1682
#define SIG_FLAG_INIT_FLOW
Definition detect.h:292
#define DETECT_DEFAULT_PRIO
Definition detect.h:52
#define SIGMATCH_STRICT_PARSING
Definition detect.h:1680
#define SIG_FLAG_SRC_ANY
Definition detect.h:241
#define SIG_FLAG_INIT_PACKET
Definition detect.h:291
DetectTable
Definition detect.h:552
@ DETECT_TABLE_APP_TD
Definition detect.h:559
@ DETECT_TABLE_PACKET_PRE_FLOW
Definition detect.h:554
@ DETECT_TABLE_PACKET_FILTER
Definition detect.h:556
@ DETECT_TABLE_APP_FILTER
Definition detect.h:558
@ DETECT_TABLE_PACKET_PRE_STREAM
Definition detect.h:555
@ DETECT_TABLE_PACKET_TD
Definition detect.h:557
#define SIG_FLAG_INIT_BIDIREC
Definition detect.h:293
#define SIG_FLAG_INIT_FILEDATA
Definition detect.h:300
@ SIG_TYPE_APP_TX
Definition detect.h:77
@ SIG_TYPE_IPONLY
Definition detect.h:66
@ SIG_TYPE_PKT
Definition detect.h:72
#define SIG_FLAG_TOSERVER
Definition detect.h:271
#define SIG_FLAG_DST_ANY
Definition detect.h:242
#define SIGMATCH_INFO_DEPRECATED
Definition detect.h:1678
#define SIGMATCH_QUOTES_MANDATORY
Definition detect.h:1668
#define SIG_FLAG_PREFILTER
Definition detect.h:278
#define SIGMATCH_QUOTES_OPTIONAL
Definition detect.h:1664
#define SIG_FLAG_FIREWALL
Definition detect.h:246
#define SIGMATCH_OPTIONAL_OPT
Definition detect.h:1661
#define SIG_FLAG_DP_ANY
Definition detect.h:244
@ DETECT_SM_LIST_MATCH
Definition detect.h:117
@ DETECT_SM_LIST_PMATCH
Definition detect.h:119
@ DETECT_SM_LIST_BASE64_DATA
Definition detect.h:124
@ DETECT_SM_LIST_THRESHOLD
Definition detect.h:133
@ DETECT_SM_LIST_SUPPRESS
Definition detect.h:132
@ DETECT_SM_LIST_TMATCH
Definition detect.h:129
@ DETECT_SM_LIST_MAX
Definition detect.h:135
@ DETECT_SM_LIST_POSTMATCH
Definition detect.h:127
@ PORT_EQ
Definition detect.h:208
SignatureHookType
Definition detect.h:546
@ SIGNATURE_HOOK_TYPE_PKT
Definition detect.h:548
@ SIGNATURE_HOOK_TYPE_APP
Definition detect.h:549
@ SIGNATURE_HOOK_TYPE_NOT_SET
Definition detect.h:547
#define SIG_FLAG_INIT_FORCE_TOCLIENT
Definition detect.h:301
#define SIG_FLAG_APPLAYER
Definition detect.h:249
#define SIG_FLAG_TXBOTHDIR
Definition detect.h:250
#define SIG_FLAG_REQUIRE_STREAM
Definition detect.h:255
#define SIGMATCH_HANDLE_NEGATION
Definition detect.h:1672
#define DETECT_MAX_RULE_SIZE
Definition detect.h:46
Flow * head
Definition flow-hash.h:1
void FlowInitConfig(bool quiet)
initialize the configuration
Definition flow.c:547
void FlowShutdown(void)
shutdown the flow engine
Definition flow.c:691
#define FLOW_QUIET
Definition flow.h:43
DecodeThreadVars * dtv
DetectEngineCtx * de_ctx
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
#define PASS
Pass the test.
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition decode.c:258
void AppLayerHtpNeedFileInspection(void)
Sets a flag that informs the HTP app layer that some module in the engine needs the http request file...
struct Thresholds ctx
void PacketRecycle(Packet *p)
Definition packet.c:150
uint64_t ts
Structure to hold thread specific data for all decode modules.
Definition decode.h:963
DetectAddress * ipv6_head
Definition detect.h:185
DetectAddress * ipv4_head
Definition detect.h:184
address structure for use in the detection engine.
Definition detect.h:168
char name[64]
Definition detect.h:450
struct DetectEngineAppInspectionEngine_ * next
Definition detect.h:441
main detection engine ctx
Definition detect.h:932
bool sigerror_silent
Definition detect.h:1026
bool * sm_types_silent_error
Definition detect.h:1112
uint8_t flags
Definition detect.h:934
enum DetectEnginePrefilterSetting prefilter_setting
Definition detect.h:1064
bool sigerror_requires
Definition detect.h:1030
const char * sigerror
Definition detect.h:1025
Signature * sig_list
Definition detect.h:941
uint32_t signum
Definition detect.h:953
bool * sm_types_prefilter
Definition detect.h:1111
HashListTable * dup_sig_hash_table
Definition detect.h:968
DetectEngineAppInspectionEngine * app_inspect_engines
Definition detect.h:1087
TransformData transforms[DETECT_TRANSFORMS_MAX]
Definition detect.h:392
DetectMetadata * list
Signature metadata list.
struct DetectMetadata_ * next
struct DetectParseRegex * next
pcre2_match_context * context
pcre2_code * regex
Port structure for detection engine.
Definition detect.h:220
uint8_t proto[256/8]
Signature reference list.
struct DetectReference_ * next
struct Flow_ * next
Definition flow.h:396
uint32_t array_size
Registration table for file handlers.
Signature * s_prev
Signature * s
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition detect.h:351
Data needed for Match()
Definition detect.h:365
bool is_last
Definition detect.h:367
SigMatchCtx * ctx
Definition detect.h:368
uint16_t type
Definition detect.h:366
a single match condition for a signature
Definition detect.h:356
uint16_t type
Definition detect.h:357
struct SigMatch_ * prev
Definition detect.h:361
struct SigMatch_ * next
Definition detect.h:360
SigMatchCtx * ctx
Definition detect.h:359
uint16_t idx
Definition detect.h:358
element in sigmatch type table.
Definition detect.h:1419
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition detect.h:1441
uint16_t alternative
Definition detect.h:1457
void(* Free)(DetectEngineCtx *, void *)
Definition detect.h:1446
uint16_t flags
Definition detect.h:1450
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition detect.h:1421
uint8_t tables
Definition detect.h:1454
const char * alias
Definition detect.h:1460
const char * name
Definition detect.h:1459
bool(* SupportsPrefilter)(const Signature *s)
Definition detect.h:1443
struct SignatureHook_::@95::@97 pkt
union SignatureHook_::@95 t
enum SignatureHookPkt ph
Definition detect.h:582
AppProto alproto
Definition detect.h:576
struct SignatureHook_::@95::@96 app
int app_progress
Definition detect.h:579
enum SignatureHookType type
Definition detect.h:572
uint32_t init_flags
Definition detect.h:608
SigMatch * mpm_sm
Definition detect.h:623
uint32_t max_content_list_id
Definition detect.h:653
bool is_rule_state_dependant
Definition detect.h:656
uint32_t buffers_size
Definition detect.h:649
bool has_possible_prefilter
Definition detect.h:605
bool src_contains_negation
Definition detect.h:601
SigMatch * prefilter_sm
Definition detect.h:625
struct SigMatch_ * smlists[DETECT_SM_LIST_MAX]
Definition detect.h:642
bool dst_contains_negation
Definition detect.h:602
AppProto alprotos[SIG_ALPROTO_MAX]
Definition detect.h:612
uint16_t sm_cnt
Definition detect.h:593
struct SigMatch_ * smlists_tail[DETECT_SM_LIST_MAX]
Definition detect.h:644
uint32_t rule_state_dependant_sids_idx
Definition detect.h:659
const DetectAddressHead * dst
Definition detect.h:639
IPOnlyCIDRItem * cidr_dst
Definition detect.h:618
IPOnlyCIDRItem * cidr_src
Definition detect.h:618
const DetectAddressHead * src
Definition detect.h:639
SignatureInitDataBuffer * buffers
Definition detect.h:647
uint32_t buffer_index
Definition detect.h:648
SignatureHook hook
Definition detect.h:590
DetectEngineTransforms transforms
Definition detect.h:631
SignatureInitDataBuffer * curbuf
Definition detect.h:650
char direction[DETECT_MAX_RULE_SIZE]
char dst[DETECT_MAX_RULE_SIZE]
char protocol[DETECT_MAX_RULE_SIZE]
char src[DETECT_MAX_RULE_SIZE]
char opts[DETECT_MAX_RULE_SIZE]
char action[DETECT_MAX_RULE_SIZE]
char sp[DETECT_MAX_RULE_SIZE]
char dp[DETECT_MAX_RULE_SIZE]
Signature container.
Definition detect.h:668
uint8_t action
Definition detect.h:683
DetectPort * sp
Definition detect.h:719
enum SignatureType type
Definition detect.h:671
uint32_t flags
Definition detect.h:669
SignatureInitData * init_data
Definition detect.h:747
uint16_t addr_dst_match6_cnt
Definition detect.h:695
DetectReference * references
Definition detect.h:741
uint8_t action_scope
Definition detect.h:690
DetectMatchAddressIPv4 * addr_src_match4
Definition detect.h:708
uint16_t addr_src_match4_cnt
Definition detect.h:694
uint16_t addr_src_match6_cnt
Definition detect.h:696
SigIntId iid
Definition detect.h:680
AppProto alproto
Definition detect.h:673
uint16_t addr_dst_match4_cnt
Definition detect.h:693
DetectMetadataHead * metadata
Definition detect.h:743
uint32_t rev
Definition detect.h:715
DetectProto proto
Definition detect.h:687
uint8_t detect_table
Definition detect.h:702
int prio
Definition detect.h:716
uint8_t file_flags
Definition detect.h:684
DetectMatchAddressIPv6 * addr_dst_match6
Definition detect.h:710
char * sig_str
Definition detect.h:745
DetectPort * dp
Definition detect.h:719
uint32_t id
Definition detect.h:713
DetectMatchAddressIPv6 * addr_src_match6
Definition detect.h:711
struct Signature_ * next
Definition detect.h:750
char * msg
Definition detect.h:736
uint8_t app_progress_hook
Definition detect.h:705
SigMatchData * sm_arrays[DETECT_SM_LIST_MAX]
Definition detect.h:731
uint32_t gid
Definition detect.h:714
DetectMatchAddressIPv4 * addr_dst_match4
Definition detect.h:707
Per thread variable structure.
Definition threadvars.h:58
void * options
Definition detect.h:388
#define BIT_U8(n)
#define BUG_ON(x)
#define MIN(x, y)
#define MAX(x, y)
#define str(s)
#define SCNtohl(x)
size_t strlcpy(char *dst, const char *src, size_t siz)
const char * name
uint32_t cnt
FILE * SCClassConfGenerateValidDummyClassConfigFD01(void)
Creates a dummy classification file, with all valid Classtypes, for testing purposes.
bool SCClassConfLoadClassificationConfigFile(DetectEngineCtx *de_ctx, FILE *fd)
Loads the Classtype info from the classification.config file.
#define SCEnter(...)
Definition util-debug.h:277
#define FatalError(...)
Definition util-debug.h:510
#define BOOL2STR(b)
Definition util-debug.h:535
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCReturnInt(x)
Definition util-debug.h:281
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition util-debug.h:255
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition util-debug.h:225
#define SCReturnPtr(x, type)
Definition util-debug.h:293
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
#define SCLogConfig(...)
Definition util-debug.h:229
#define SCReturn
Definition util-debug.h:279
void * HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen)
int HashListTableAdd(HashListTable *ht, void *data, uint16_t datalen)
HashListTable * HashListTableInit(uint32_t size, uint32_t(*Hash)(struct HashListTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
void HashListTableFree(HashListTable *ht)
#define SCFree(p)
Definition util-mem.h:61
#define SCRealloc(ptr, sz)
Definition util-mem.h:50
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define SCStrdup(s)
Definition util-mem.h:56
#define unlikely(expr)
uint64_t offset
int UTHMatchPackets(DetectEngineCtx *de_ctx, Packet **p, int num_packets)
int UTHAppendSigs(DetectEngineCtx *de_ctx, const char *sigs[], int numsigs)
UTHAppendSigs: Add sigs to the detection_engine checking for errors.
int UTHCheckPacketMatchResults(Packet *p, uint32_t sids[], uint32_t results[], int numsigs)
UTHCheckPacketMatches: function to check if a packet match some sids.
Packet * UTHBuildPacketFromEth(uint8_t *raw_eth, uint16_t pktsize)
UTHBuildPacketFromEth is a wrapper that build a packet for the rawbytes.
#define DEBUG_VALIDATE_BUG_ON(exp)