1 /* Copyright (C) 2007-2020 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18 /**
19 * \file
20 *
21 * \author Victor Julien <victor@inliniac.net>
22 *
23 * signature parser
24 */
25
26 #include "suricata-common.h"
27 #include "debug.h"
28
29 #include "detect.h"
30 #include "detect-engine.h"
31 #include "detect-engine-address.h"
32 #include "detect-engine-port.h"
33 #include "detect-engine-mpm.h"
34 #include "detect-engine-state.h"
35
36 #include "detect-content.h"
37 #include "detect-pcre.h"
38 #include "detect-uricontent.h"
39 #include "detect-reference.h"
40 #include "detect-ipproto.h"
41 #include "detect-flow.h"
42 #include "detect-app-layer-protocol.h"
43 #include "detect-lua.h"
44 #include "detect-app-layer-event.h"
45 #include "detect-http-method.h"
46
47 #include "pkt-var.h"
48 #include "host.h"
49 #include "util-profiling.h"
50 #include "decode.h"
51
52 #include "flow.h"
53
54 #include "util-rule-vars.h"
55 #include "conf.h"
56 #include "conf-yaml-loader.h"
57
58 #include "app-layer.h"
59 #include "app-layer-protos.h"
60 #include "app-layer-parser.h"
61 #include "app-layer-htp.h"
62
63 #include "util-classification-config.h"
64 #include "util-unittest.h"
65 #include "util-unittest-helper.h"
66 #include "util-debug.h"
67 #include "string.h"
68 #include "detect-parse.h"
69 #include "detect-engine-iponly.h"
70 #include "app-layer-detect-proto.h"
71
72 /* Table with all SigMatch registrations */
73 SigTableElmt sigmatch_table[DETECT_TBLSIZE];
74
75 extern int sc_set_caps;
76
77 static void SigMatchTransferSigMatchAcrossLists(SigMatch *sm,
78 SigMatch **src_sm_list, SigMatch **src_sm_list_tail,
79 SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail);
80
81 /**
82 * \brief We use this as data to the hash table DetectEngineCtx->dup_sig_hash_table.
83 */
84 typedef struct SigDuplWrapper_ {
85 /* the signature we want to wrap */
86 Signature *s;
87 /* the signature right before the above signature in the det_ctx->sig_list */
88 Signature *s_prev;
89 } SigDuplWrapper;
90
91 #define CONFIG_PARTS 8
92
93 #define CONFIG_ACTION 0
94 #define CONFIG_PROTO 1
95 #define CONFIG_SRC 2
96 #define CONFIG_SP 3
97 #define CONFIG_DIREC 4
98 #define CONFIG_DST 5
99 #define CONFIG_DP 6
100 #define CONFIG_OPTS 7
101
102 /** helper structure for sig parsing */
103 typedef struct SignatureParser_ {
104 char action[DETECT_MAX_RULE_SIZE];
105 char protocol[DETECT_MAX_RULE_SIZE];
106 char direction[DETECT_MAX_RULE_SIZE];
107 char src[DETECT_MAX_RULE_SIZE];
108 char dst[DETECT_MAX_RULE_SIZE];
109 char sp[DETECT_MAX_RULE_SIZE];
110 char dp[DETECT_MAX_RULE_SIZE];
111 char opts[DETECT_MAX_RULE_SIZE];
112 } SignatureParser;
113
DetectListToHumanString(int list)114 const char *DetectListToHumanString(int list)
115 {
116 #define CASE_CODE_STRING(E, S) case E: return S; break
117 switch (list) {
118 CASE_CODE_STRING(DETECT_SM_LIST_MATCH, "packet");
119 CASE_CODE_STRING(DETECT_SM_LIST_PMATCH, "payload");
120 CASE_CODE_STRING(DETECT_SM_LIST_TMATCH, "tag");
121 CASE_CODE_STRING(DETECT_SM_LIST_POSTMATCH, "postmatch");
122 CASE_CODE_STRING(DETECT_SM_LIST_SUPPRESS, "suppress");
123 CASE_CODE_STRING(DETECT_SM_LIST_THRESHOLD, "threshold");
124 CASE_CODE_STRING(DETECT_SM_LIST_MAX, "max (internal)");
125 }
126 #undef CASE_CODE_STRING
127 return "unknown";
128 }
129
130 #define CASE_CODE(E) case E: return #E
DetectListToString(int list)131 const char *DetectListToString(int list)
132 {
133 switch (list) {
134 CASE_CODE(DETECT_SM_LIST_MATCH);
135 CASE_CODE(DETECT_SM_LIST_PMATCH);
136 CASE_CODE(DETECT_SM_LIST_TMATCH);
137 CASE_CODE(DETECT_SM_LIST_POSTMATCH);
138 CASE_CODE(DETECT_SM_LIST_SUPPRESS);
139 CASE_CODE(DETECT_SM_LIST_THRESHOLD);
140 CASE_CODE(DETECT_SM_LIST_MAX);
141 }
142 return "unknown";
143 }
144
145 /** \param arg NULL or empty string */
DetectEngineContentModifierBufferSetup(DetectEngineCtx * de_ctx,Signature * s,const char * arg,int sm_type,int sm_list,AppProto alproto)146 int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx,
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(SC_ERR_INVALID_ARGUMENT, "%s shouldn't be supplied "
155 "with an argument", sigmatch_table[sm_type].name);
156 goto end;
157 }
158
159 if (s->init_data->list != DETECT_SM_LIST_NOTSET) {
160 SCLogError(SC_ERR_INVALID_SIGNATURE, "\"%s\" keyword seen "
161 "with a sticky buffer still set. Reset sticky buffer "
162 "with pkt_data before using the modifier.",
163 sigmatch_table[sm_type].name);
164 goto end;
165 }
166 if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(s->alproto, alproto)) {
167 SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting "
168 "alprotos set");
169 goto end;
170 }
171
172 sm = DetectGetLastSMByListId(s,
173 DETECT_SM_LIST_PMATCH, DETECT_CONTENT, -1);
174 if (sm == NULL) {
175 SCLogError(SC_ERR_INVALID_SIGNATURE, "\"%s\" keyword "
176 "found inside the rule without a content context. "
177 "Please use a \"content\" keyword before using the "
178 "\"%s\" keyword", sigmatch_table[sm_type].name,
179 sigmatch_table[sm_type].name);
180 goto end;
181 }
182 DetectContentData *cd = (DetectContentData *)sm->ctx;
183 if (cd->flags & DETECT_CONTENT_RAWBYTES) {
184 SCLogError(SC_ERR_INVALID_SIGNATURE, "%s rule can not "
185 "be used with the rawbytes rule keyword",
186 sigmatch_table[sm_type].name);
187 goto end;
188 }
189 if (cd->flags & DETECT_CONTENT_REPLACE) {
190 SCLogError(SC_ERR_INVALID_SIGNATURE, "%s rule can not "
191 "be used with the replace rule keyword",
192 sigmatch_table[sm_type].name);
193 goto end;
194 }
195 if (cd->flags & (DETECT_CONTENT_WITHIN | DETECT_CONTENT_DISTANCE)) {
196 SigMatch *pm = DetectGetLastSMByListPtr(s, sm->prev,
197 DETECT_CONTENT, DETECT_PCRE, -1);
198 if (pm != NULL) {
199 if (pm->type == DETECT_CONTENT) {
200 DetectContentData *tmp_cd = (DetectContentData *)pm->ctx;
201 tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT;
202 } else {
203 DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx;
204 tmp_pd->flags &= ~DETECT_PCRE_RELATIVE_NEXT;
205 }
206 }
207
208 pm = DetectGetLastSMByListId(s, sm_list,
209 DETECT_CONTENT, DETECT_PCRE, -1);
210 if (pm != NULL) {
211 if (pm->type == DETECT_CONTENT) {
212 DetectContentData *tmp_cd = (DetectContentData *)pm->ctx;
213 tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT;
214 } else {
215 DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx;
216 tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT;
217 }
218 }
219 }
220 s->alproto = alproto;
221 s->flags |= SIG_FLAG_APPLAYER;
222
223 /* transfer the sm from the pmatch list to sm_list */
224 SigMatchTransferSigMatchAcrossLists(sm,
225 &s->init_data->smlists[DETECT_SM_LIST_PMATCH],
226 &s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH],
227 &s->init_data->smlists[sm_list],
228 &s->init_data->smlists_tail[sm_list]);
229
230 ret = 0;
231 end:
232 return ret;
233 }
234
SigMatchAlloc(void)235 SigMatch *SigMatchAlloc(void)
236 {
237 SigMatch *sm = SCMalloc(sizeof(SigMatch));
238 if (unlikely(sm == NULL))
239 return NULL;
240
241 memset(sm, 0, sizeof(SigMatch));
242 sm->prev = NULL;
243 sm->next = NULL;
244 return sm;
245 }
246
247 /** \brief free a SigMatch
248 * \param sm SigMatch to free.
249 */
SigMatchFree(DetectEngineCtx * de_ctx,SigMatch * sm)250 void SigMatchFree(DetectEngineCtx *de_ctx, SigMatch *sm)
251 {
252 if (sm == NULL)
253 return;
254
255 /** free the ctx, for that we call the Free func */
256 if (sm->ctx != NULL) {
257 if (sigmatch_table[sm->type].Free != NULL) {
258 sigmatch_table[sm->type].Free(de_ctx, sm->ctx);
259 }
260 }
261 SCFree(sm);
262 }
263
SigTableGetIndex(const SigTableElmt * e)264 static enum DetectKeywordId SigTableGetIndex(const SigTableElmt *e)
265 {
266 const SigTableElmt *table = &sigmatch_table[0];
267 ptrdiff_t offset = e - table;
268 BUG_ON(offset >= DETECT_TBLSIZE);
269 return (enum DetectKeywordId)offset;
270 }
271
272 /* Get the detection module by name */
SigTableGet(char * name)273 static SigTableElmt *SigTableGet(char *name)
274 {
275 SigTableElmt *st = NULL;
276 int i = 0;
277
278 for (i = 0; i < DETECT_TBLSIZE; i++) {
279 st = &sigmatch_table[i];
280
281 if (st->name != NULL) {
282 if (strcasecmp(name,st->name) == 0)
283 return st;
284 if (st->alias != NULL && strcasecmp(name,st->alias) == 0)
285 return st;
286 }
287 }
288
289 return NULL;
290 }
291
SigMatchSilentErrorEnabled(const DetectEngineCtx * de_ctx,const enum DetectKeywordId id)292 bool SigMatchSilentErrorEnabled(const DetectEngineCtx *de_ctx,
293 const enum DetectKeywordId id)
294 {
295 return de_ctx->sm_types_silent_error[id];
296 }
297
SigMatchStrictEnabled(const enum DetectKeywordId id)298 bool SigMatchStrictEnabled(const enum DetectKeywordId id)
299 {
300 if (id < DETECT_TBLSIZE) {
301 return ((sigmatch_table[id].flags & SIGMATCH_STRICT_PARSING) != 0);
302 }
303 return false;
304 }
305
SigTableApplyStrictCommandlineOption(const char * str)306 void SigTableApplyStrictCommandlineOption(const char *str)
307 {
308 if (str == NULL) {
309 /* nothing to be done */
310 return;
311 }
312
313 /* "all" just sets the flag for each keyword */
314 if (strcmp(str, "all") == 0) {
315 for (int i = 0; i < DETECT_TBLSIZE; i++) {
316 SigTableElmt *st = &sigmatch_table[i];
317 st->flags |= SIGMATCH_STRICT_PARSING;
318 }
319 return;
320 }
321
322 char *copy = SCStrdup(str);
323 if (copy == NULL)
324 FatalError(SC_ERR_MEM_ALLOC, "could not duplicate opt string");
325
326 char *xsaveptr = NULL;
327 char *key = strtok_r(copy, ",", &xsaveptr);
328 while (key != NULL) {
329 SigTableElmt *st = SigTableGet(key);
330 if (st != NULL) {
331 st->flags |= SIGMATCH_STRICT_PARSING;
332 } else {
333 SCLogWarning(SC_ERR_CMD_LINE, "'strict' command line "
334 "argument '%s' not found", key);
335 }
336 key = strtok_r(NULL, ",", &xsaveptr);
337 }
338
339 SCFree(copy);
340 }
341
342 /**
343 * \brief Append a SigMatch to the list type.
344 *
345 * \param s Signature.
346 * \param new The sig match to append.
347 * \param list The list to append to.
348 */
SigMatchAppendSMToList(Signature * s,SigMatch * new,int list)349 void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list)
350 {
351 if (list > 0 && (uint32_t)list >= s->init_data->smlists_array_size)
352 {
353 uint32_t old_size = s->init_data->smlists_array_size;
354 uint32_t new_size = (uint32_t)list + 1;
355 void *ptr = SCRealloc(s->init_data->smlists, (new_size * sizeof(SigMatch *)));
356 if (ptr == NULL)
357 abort();
358 s->init_data->smlists = ptr;
359 ptr = SCRealloc(s->init_data->smlists_tail, (new_size * sizeof(SigMatch *)));
360 if (ptr == NULL)
361 abort();
362 s->init_data->smlists_tail = ptr;
363 for (uint32_t i = old_size; i < new_size; i++) {
364 s->init_data->smlists[i] = NULL;
365 s->init_data->smlists_tail[i] = NULL;
366 }
367 s->init_data->smlists_array_size = new_size;
368 }
369
370 if (s->init_data->smlists[list] == NULL) {
371 s->init_data->smlists[list] = new;
372 s->init_data->smlists_tail[list] = new;
373 new->next = NULL;
374 new->prev = NULL;
375 } else {
376 SigMatch *cur = s->init_data->smlists_tail[list];
377 cur->next = new;
378 new->prev = cur;
379 new->next = NULL;
380 s->init_data->smlists_tail[list] = new;
381 }
382
383 new->idx = s->init_data->sm_cnt;
384 s->init_data->sm_cnt++;
385 }
386
SigMatchRemoveSMFromList(Signature * s,SigMatch * sm,int sm_list)387 void SigMatchRemoveSMFromList(Signature *s, SigMatch *sm, int sm_list)
388 {
389 if (sm == s->init_data->smlists[sm_list]) {
390 s->init_data->smlists[sm_list] = sm->next;
391 }
392 if (sm == s->init_data->smlists_tail[sm_list]) {
393 s->init_data->smlists_tail[sm_list] = sm->prev;
394 }
395 if (sm->prev != NULL)
396 sm->prev->next = sm->next;
397 if (sm->next != NULL)
398 sm->next->prev = sm->prev;
399
400 return;
401 }
402
403 /**
404 * \brief Returns a pointer to the last SigMatch instance of a particular type
405 * in a Signature of the payload list.
406 *
407 * \param s Pointer to the tail of the sigmatch list
408 * \param type SigMatch type which has to be searched for in the Signature.
409 *
410 * \retval match Pointer to the last SigMatch instance of type 'type'.
411 */
SigMatchGetLastSMByType(SigMatch * sm,int type)412 static SigMatch *SigMatchGetLastSMByType(SigMatch *sm, int type)
413 {
414 while (sm != NULL) {
415 if (sm->type == type) {
416 return sm;
417 }
418 sm = sm->prev;
419 }
420
421 return NULL;
422 }
423
424 /** \brief get the last SigMatch from lists that support
425 * MPM.
426 * \note only supports the lists that are registered through
427 * DetectBufferTypeSupportsMpm().
428 */
DetectGetLastSMFromMpmLists(const DetectEngineCtx * de_ctx,const Signature * s)429 SigMatch *DetectGetLastSMFromMpmLists(const DetectEngineCtx *de_ctx, const Signature *s)
430 {
431 SigMatch *sm_last = NULL;
432 SigMatch *sm_new;
433 uint32_t sm_type;
434
435 /* if we have a sticky buffer, use that */
436 if (s->init_data->list != DETECT_SM_LIST_NOTSET) {
437 if (!(DetectBufferTypeSupportsMpmGetById(de_ctx, s->init_data->list))) {
438 return NULL;
439 }
440
441 sm_last = DetectGetLastSMByListPtr(s,
442 s->init_data->smlists_tail[s->init_data->list],
443 DETECT_CONTENT, -1);
444 return sm_last;
445 }
446
447 /* otherwise brute force it */
448 for (sm_type = 0; sm_type < s->init_data->smlists_array_size; sm_type++) {
449 if (!DetectBufferTypeSupportsMpmGetById(de_ctx, sm_type))
450 continue;
451 SigMatch *sm_list = s->init_data->smlists_tail[sm_type];
452 sm_new = SigMatchGetLastSMByType(sm_list, DETECT_CONTENT);
453 if (sm_new == NULL)
454 continue;
455 if (sm_last == NULL || sm_new->idx > sm_last->idx)
456 sm_last = sm_new;
457 }
458
459 return sm_last;
460 }
461
462 /**
463 * \brief Returns the sm with the largest index (added latest) from the lists
464 * passed to us.
465 *
466 * \retval Pointer to Last sm.
467 */
DetectGetLastSMFromLists(const Signature * s,...)468 SigMatch *DetectGetLastSMFromLists(const Signature *s, ...)
469 {
470 SigMatch *sm_last = NULL;
471 SigMatch *sm_new;
472
473 /* otherwise brute force it */
474 for (int buf_type = 0; buf_type < (int)s->init_data->smlists_array_size; buf_type++) {
475 if (s->init_data->smlists[buf_type] == NULL)
476 continue;
477 if (s->init_data->list != DETECT_SM_LIST_NOTSET &&
478 buf_type != s->init_data->list)
479 continue;
480
481 int sm_type;
482 va_list ap;
483 va_start(ap, s);
484
485 for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int))
486 {
487 sm_new = SigMatchGetLastSMByType(s->init_data->smlists_tail[buf_type], sm_type);
488 if (sm_new == NULL)
489 continue;
490 if (sm_last == NULL || sm_new->idx > sm_last->idx)
491 sm_last = sm_new;
492 }
493 va_end(ap);
494 }
495
496 return sm_last;
497 }
498
499 /**
500 * \brief Returns the sm with the largest index (added last) from the list
501 * passed to us as a pointer.
502 *
503 * \param sm_list pointer to the SigMatch we should look before
504 * \param va_args list of keyword types terminated by -1
505 *
506 * \retval sm_last to last sm.
507 */
DetectGetLastSMByListPtr(const Signature * s,SigMatch * sm_list,...)508 SigMatch *DetectGetLastSMByListPtr(const Signature *s, SigMatch *sm_list, ...)
509 {
510 SigMatch *sm_last = NULL;
511 SigMatch *sm_new;
512 int sm_type;
513
514 va_list ap;
515 va_start(ap, sm_list);
516
517 for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int))
518 {
519 sm_new = SigMatchGetLastSMByType(sm_list, sm_type);
520 if (sm_new == NULL)
521 continue;
522 if (sm_last == NULL || sm_new->idx > sm_last->idx)
523 sm_last = sm_new;
524 }
525
526 va_end(ap);
527
528 return sm_last;
529 }
530
531 /**
532 * \brief Returns the sm with the largest index (added last) from the list
533 * passed to us as an id.
534 *
535 * \param list_id id of the list to be searched
536 * \param va_args list of keyword types terminated by -1
537 *
538 * \retval sm_last to last sm.
539 */
DetectGetLastSMByListId(const Signature * s,int list_id,...)540 SigMatch *DetectGetLastSMByListId(const Signature *s, int list_id, ...)
541 {
542 SigMatch *sm_last = NULL;
543 SigMatch *sm_new;
544 int sm_type;
545
546 if ((uint32_t)list_id >= s->init_data->smlists_array_size) {
547 return NULL;
548 }
549 SigMatch *sm_list = s->init_data->smlists_tail[list_id];
550 if (sm_list == NULL)
551 return NULL;
552
553 va_list ap;
554 va_start(ap, list_id);
555
556 for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int))
557 {
558 sm_new = SigMatchGetLastSMByType(sm_list, sm_type);
559 if (sm_new == NULL)
560 continue;
561 if (sm_last == NULL || sm_new->idx > sm_last->idx)
562 sm_last = sm_new;
563 }
564
565 va_end(ap);
566
567 return sm_last;
568 }
569
570 /**
571 * \brief Returns the sm with the largest index (added latest) from this sig
572 *
573 * \retval sm_last Pointer to last sm
574 */
DetectGetLastSM(const Signature * s)575 SigMatch *DetectGetLastSM(const Signature *s)
576 {
577 const int nlists = s->init_data->smlists_array_size;
578 SigMatch *sm_last = NULL;
579 SigMatch *sm_new;
580 int i;
581
582 for (i = 0; i < nlists; i ++) {
583 sm_new = s->init_data->smlists_tail[i];
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
590 return sm_last;
591 }
592
SigMatchTransferSigMatchAcrossLists(SigMatch * sm,SigMatch ** src_sm_list,SigMatch ** src_sm_list_tail,SigMatch ** dst_sm_list,SigMatch ** dst_sm_list_tail)593 static void SigMatchTransferSigMatchAcrossLists(SigMatch *sm,
594 SigMatch **src_sm_list, SigMatch **src_sm_list_tail,
595 SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail)
596 {
597 /* we won't do any checks for args */
598
599 if (sm->prev != NULL)
600 sm->prev->next = sm->next;
601 if (sm->next != NULL)
602 sm->next->prev = sm->prev;
603
604 if (sm == *src_sm_list)
605 *src_sm_list = sm->next;
606 if (sm == *src_sm_list_tail)
607 *src_sm_list_tail = sm->prev;
608
609 if (*dst_sm_list == NULL) {
610 *dst_sm_list = sm;
611 *dst_sm_list_tail = sm;
612 sm->next = NULL;
613 sm->prev = NULL;
614 } else {
615 SigMatch *cur = *dst_sm_list_tail;
616 cur->next = sm;
617 sm->prev = cur;
618 sm->next = NULL;
619 *dst_sm_list_tail = sm;
620 }
621
622 return;
623 }
624
SigMatchListSMBelongsTo(const Signature * s,const SigMatch * key_sm)625 int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm)
626 {
627 if (key_sm == NULL)
628 return -1;
629
630 const int nlists = s->init_data->smlists_array_size;
631 for (int list = 0; list < nlists; list++) {
632 const SigMatch *sm = s->init_data->smlists[list];
633 while (sm != NULL) {
634 if (sm == key_sm)
635 return list;
636 sm = sm->next;
637 }
638 }
639
640 SCLogError(SC_ERR_INVALID_SIGNATURE, "Unable to find the sm in any of the "
641 "sm lists");
642 return -1;
643 }
644
SigParseOptions(DetectEngineCtx * de_ctx,Signature * s,char * optstr,char * output,size_t output_size)645 static int SigParseOptions(DetectEngineCtx *de_ctx, Signature *s, char *optstr, char *output, size_t output_size)
646 {
647 SigTableElmt *st = NULL;
648 char *optname = NULL;
649 char *optvalue = NULL;
650
651 /* Trim leading space. */
652 while (isblank(*optstr)) {
653 optstr++;
654 }
655
656 /* Look for the end of this option, handling escaped semicolons. */
657 char *optend = optstr;
658 for (;;) {
659 optend = strchr(optend, ';');
660 if (optend == NULL) {
661 SCLogError(SC_ERR_INVALID_SIGNATURE, "no terminating \";\" found");
662 goto error;
663 }
664 else if (optend > optstr && *(optend -1 ) == '\\') {
665 optend++;
666 } else {
667 break;
668 }
669 }
670 *(optend++) = '\0';
671
672 /* Find the start of the option value. */
673 char *optvalptr = strchr(optstr, ':');
674 if (optvalptr) {
675 *(optvalptr++) = '\0';
676
677 /* Trim trailing space from name. */
678 for (size_t i = strlen(optvalptr); i > 0; i--) {
679 if (isblank(optvalptr[i - 1])) {
680 optvalptr[i - 1] = '\0';
681 } else {
682 break;
683 }
684 }
685
686 optvalue = optvalptr;
687 }
688
689 /* Trim trailing space from name. */
690 for (size_t i = strlen(optstr); i > 0; i--) {
691 if (isblank(optstr[i - 1])) {
692 optstr[i - 1] = '\0';
693 } else {
694 break;
695 }
696 }
697 optname = optstr;
698
699 /* Call option parsing */
700 st = SigTableGet(optname);
701 if (st == NULL || st->Setup == NULL) {
702 SCLogError(SC_ERR_RULE_KEYWORD_UNKNOWN, "unknown rule keyword '%s'.", optname);
703 goto error;
704 }
705
706 if (!(st->flags & (SIGMATCH_NOOPT|SIGMATCH_OPTIONAL_OPT))) {
707 if (optvalue == NULL || strlen(optvalue) == 0) {
708 SCLogError(SC_ERR_INVALID_SIGNATURE,
709 "invalid formatting or malformed option to %s keyword: '%s'", optname, optstr);
710 goto error;
711 }
712 } else if (st->flags & SIGMATCH_NOOPT) {
713 if (optvalue && strlen(optvalue)) {
714 SCLogError(SC_ERR_INVALID_SIGNATURE, "unexpected option to %s keyword: '%s'", optname,
715 optstr);
716 goto error;
717 }
718 }
719 s->init_data->negated = false;
720
721 if (st->flags & SIGMATCH_INFO_DEPRECATED) {
722 #define URL "https://suricata-ids.org/about/deprecation-policy/"
723 if (st->alternative == 0)
724 SCLogWarning(SC_WARN_DEPRECATED, "keyword '%s' is deprecated "
725 "and will be removed soon. See %s", st->name, URL);
726 else
727 SCLogWarning(SC_WARN_DEPRECATED, "keyword '%s' is deprecated "
728 "and will be removed soon. Use '%s' instead. "
729 "See %s", st->name, sigmatch_table[st->alternative].name, URL);
730 #undef URL
731 }
732
733 int setup_ret = 0;
734
735 /* Validate double quoting, trimming trailing white space along the way. */
736 if (optvalue != NULL && strlen(optvalue) > 0) {
737 size_t ovlen = strlen(optvalue);
738 char *ptr = optvalue;
739
740 /* skip leading whitespace */
741 while (ovlen > 0) {
742 if (!isblank(*ptr))
743 break;
744 ptr++;
745 ovlen--;
746 }
747 if (ovlen == 0) {
748 SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid formatting or malformed option to %s keyword: \'%s\'",
749 optname, optstr);
750 goto error;
751 }
752
753 /* see if value is negated */
754 if ((st->flags & SIGMATCH_HANDLE_NEGATION) && *ptr == '!') {
755 s->init_data->negated = true;
756 ptr++;
757 ovlen--;
758 }
759 /* skip more whitespace */
760 while (ovlen > 0) {
761 if (!isblank(*ptr))
762 break;
763 ptr++;
764 ovlen--;
765 }
766 if (ovlen == 0) {
767 SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid formatting or malformed option to %s keyword: \'%s\'",
768 optname, optstr);
769 goto error;
770 }
771 /* if quoting is mandatory, enforce it */
772 if (st->flags & SIGMATCH_QUOTES_MANDATORY && ovlen && *ptr != '"') {
773 SCLogError(SC_ERR_INVALID_SIGNATURE, "invalid formatting to %s keyword: "
774 "value must be double quoted \'%s\'", optname, optstr);
775 goto error;
776 }
777
778 if ((st->flags & (SIGMATCH_QUOTES_OPTIONAL|SIGMATCH_QUOTES_MANDATORY))
779 && ovlen && *ptr == '"')
780 {
781 for (; ovlen > 0; ovlen--) {
782 if (isblank(ptr[ovlen - 1])) {
783 ptr[ovlen - 1] = '\0';
784 } else {
785 break;
786 }
787 }
788 if (ovlen && ptr[ovlen - 1] != '"') {
789 SCLogError(SC_ERR_INVALID_SIGNATURE,
790 "bad option value formatting (possible missing semicolon) "
791 "for keyword %s: \'%s\'", optname, optvalue);
792 goto error;
793 }
794 if (ovlen > 1) {
795 /* strip leading " */
796 ptr++;
797 ovlen--;
798 ptr[ovlen - 1] = '\0';
799 ovlen--;
800 }
801 if (ovlen == 0) {
802 SCLogError(SC_ERR_INVALID_SIGNATURE,
803 "bad input "
804 "for keyword %s: \'%s\'", optname, optvalue);
805 goto error;
806 }
807 } else {
808 if (*ptr == '"') {
809 SCLogError(SC_ERR_INVALID_SIGNATURE, "quotes on %s keyword that doesn't support them: \'%s\'",
810 optname, optstr);
811 goto error;
812 }
813 }
814 /* setup may or may not add a new SigMatch to the list */
815 setup_ret = st->Setup(de_ctx, s, ptr);
816 } else {
817 /* setup may or may not add a new SigMatch to the list */
818 setup_ret = st->Setup(de_ctx, s, NULL);
819 }
820 if (setup_ret < 0) {
821 SCLogDebug("\"%s\" failed to setup", st->name);
822
823 /* handle 'silent' error case */
824 if (setup_ret == -2) {
825 enum DetectKeywordId idx = SigTableGetIndex(st);
826 if (de_ctx->sm_types_silent_error[idx] == false) {
827 de_ctx->sm_types_silent_error[idx] = true;
828 return -1;
829 }
830 return -2;
831 }
832 return setup_ret;
833 }
834 s->init_data->negated = false;
835
836 if (strlen(optend) > 0) {
837 strlcpy(output, optend, output_size);
838 return 1;
839 }
840
841 return 0;
842
843 error:
844 return -1;
845 }
846
847 /** \brief Parse address string and update signature
848 *
849 * \retval 0 ok, -1 error
850 */
SigParseAddress(DetectEngineCtx * de_ctx,Signature * s,const char * addrstr,char flag)851 static int SigParseAddress(DetectEngineCtx *de_ctx,
852 Signature *s, const char *addrstr, char flag)
853 {
854 SCLogDebug("Address Group \"%s\" to be parsed now", addrstr);
855
856 /* pass on to the address(list) parser */
857 if (flag == 0) {
858 if (strcasecmp(addrstr, "any") == 0)
859 s->flags |= SIG_FLAG_SRC_ANY;
860
861 s->init_data->src = DetectParseAddress(de_ctx, addrstr,
862 &s->init_data->src_contains_negation);
863 if (s->init_data->src == NULL)
864 goto error;
865 } else {
866 if (strcasecmp(addrstr, "any") == 0)
867 s->flags |= SIG_FLAG_DST_ANY;
868
869 s->init_data->dst = DetectParseAddress(de_ctx, addrstr,
870 &s->init_data->dst_contains_negation);
871 if (s->init_data->dst == NULL)
872 goto error;
873 }
874
875 return 0;
876
877 error:
878 return -1;
879 }
880
881 /**
882 * \brief Parses the protocol supplied by the Signature.
883 *
884 * http://www.iana.org/assignments/protocol-numbers
885 *
886 * \param s Pointer to the Signature instance to which the parsed
887 * protocol has to be added.
888 * \param protostr Pointer to the character string containing the protocol name.
889 *
890 * \retval 0 On successfully parsing the protocl sent as the argument.
891 * \retval -1 On failure
892 */
SigParseProto(Signature * s,const char * protostr)893 static int SigParseProto(Signature *s, const char *protostr)
894 {
895 SCEnter();
896
897 int r = DetectProtoParse(&s->proto, (char *)protostr);
898 if (r < 0) {
899 s->alproto = AppLayerGetProtoByName((char *)protostr);
900 /* indicate that the signature is app-layer */
901 if (s->alproto != ALPROTO_UNKNOWN) {
902 s->flags |= SIG_FLAG_APPLAYER;
903
904 AppLayerProtoDetectSupportedIpprotos(s->alproto, s->proto.proto);
905 }
906 else {
907 SCLogError(SC_ERR_UNKNOWN_PROTOCOL, "protocol \"%s\" cannot be used "
908 "in a signature. Either detection for this protocol "
909 "is not yet supported OR detection has been disabled for "
910 "protocol through the yaml option "
911 "app-layer.protocols.%s.detection-enabled", protostr,
912 protostr);
913 SCReturnInt(-1);
914 }
915 }
916
917 /* if any of these flags are set they are set in a mutually exclusive
918 * manner */
919 if (s->proto.flags & DETECT_PROTO_ONLY_PKT) {
920 s->flags |= SIG_FLAG_REQUIRE_PACKET;
921 } else if (s->proto.flags & DETECT_PROTO_ONLY_STREAM) {
922 s->flags |= SIG_FLAG_REQUIRE_STREAM;
923 }
924
925 SCReturnInt(0);
926 }
927
928 /**
929 * \brief Parses the port(source or destination) field, from a Signature.
930 *
931 * \param s Pointer to the signature which has to be updated with the
932 * port information.
933 * \param portstr Pointer to the character string containing the port info.
934 * \param Flag which indicates if the portstr received is src or dst
935 * port. For src port: flag = 0, dst port: flag = 1.
936 *
937 * \retval 0 On success.
938 * \retval -1 On failure.
939 */
SigParsePort(const DetectEngineCtx * de_ctx,Signature * s,const char * portstr,char flag)940 static int SigParsePort(const DetectEngineCtx *de_ctx,
941 Signature *s, const char *portstr, char flag)
942 {
943 int r = 0;
944
945 /* XXX VJ exclude handling this for none UDP/TCP proto's */
946
947 SCLogDebug("Port group \"%s\" to be parsed", portstr);
948
949 if (flag == 0) {
950 if (strcasecmp(portstr, "any") == 0)
951 s->flags |= SIG_FLAG_SP_ANY;
952
953 r = DetectPortParse(de_ctx, &s->sp, (char *)portstr);
954 } else if (flag == 1) {
955 if (strcasecmp(portstr, "any") == 0)
956 s->flags |= SIG_FLAG_DP_ANY;
957
958 r = DetectPortParse(de_ctx, &s->dp, (char *)portstr);
959 }
960
961 if (r < 0)
962 return -1;
963
964 return 0;
965 }
966
967 /** \retval 1 valid
968 * \retval 0 invalid
969 */
SigParseActionRejectValidate(const char * action)970 static int SigParseActionRejectValidate(const char *action)
971 {
972 #ifdef HAVE_LIBNET11
973 #if defined HAVE_LIBCAP_NG && !defined HAVE_LIBNET_CAPABILITIES
974 if (sc_set_caps == TRUE) {
975 SCLogError(SC_ERR_LIBNET11_INCOMPATIBLE_WITH_LIBCAP_NG, "Libnet 1.1 is "
976 "incompatible with POSIX based capabilities with privs dropping. "
977 "For rejects to work, run as root/super user.");
978 return 0;
979 }
980 #endif
981 #else /* no libnet 1.1 */
982 SCLogError(SC_ERR_LIBNET_REQUIRED_FOR_ACTION, "Libnet 1.1.x is "
983 "required for action \"%s\" but is not compiled into Suricata",
984 action);
985 return 0;
986 #endif
987 return 1;
988 }
989
990 /**
991 * \brief Parses the action that has been used by the Signature and allots it
992 * to its Signature instance.
993 *
994 * \param s Pointer to the Signature instance to which the action belongs.
995 * \param action Pointer to the action string used by the Signature.
996 *
997 * \retval 0 On successfully parsing the action string and adding it to the
998 * Signature.
999 * \retval -1 On failure.
1000 */
SigParseAction(Signature * s,const char * action)1001 static int SigParseAction(Signature *s, const char *action)
1002 {
1003 if (strcasecmp(action, "alert") == 0) {
1004 s->action = ACTION_ALERT;
1005 } else if (strcasecmp(action, "drop") == 0) {
1006 s->action = ACTION_DROP;
1007 } else if (strcasecmp(action, "pass") == 0) {
1008 s->action = ACTION_PASS;
1009 } else if (strcasecmp(action, "reject") == 0 ||
1010 strcasecmp(action, "rejectsrc") == 0)
1011 {
1012 if (!(SigParseActionRejectValidate(action)))
1013 return -1;
1014 s->action = ACTION_REJECT|ACTION_DROP;
1015 } else if (strcasecmp(action, "rejectdst") == 0) {
1016 if (!(SigParseActionRejectValidate(action)))
1017 return -1;
1018 s->action = ACTION_REJECT_DST|ACTION_DROP;
1019 } else if (strcasecmp(action, "rejectboth") == 0) {
1020 if (!(SigParseActionRejectValidate(action)))
1021 return -1;
1022 s->action = ACTION_REJECT_BOTH|ACTION_DROP;
1023 } else if (strcasecmp(action, "config") == 0) {
1024 s->action = ACTION_CONFIG;
1025 s->flags |= SIG_FLAG_NOALERT;
1026 } else {
1027 SCLogError(SC_ERR_INVALID_ACTION,"An invalid action \"%s\" was given",action);
1028 return -1;
1029 }
1030 return 0;
1031 }
1032
1033 /**
1034 * \brief Parse the next token in rule.
1035 *
1036 * For rule parsing a token is considered to be a string of characters
1037 * separated by white space.
1038 *
1039 * \param input double pointer to input buffer, will be advanced as input is
1040 * parsed.
1041 * \param output buffer to copy token into.
1042 * \param output_size length of output buffer.
1043 */
SigParseToken(char ** input,char * output,const size_t output_size)1044 static inline int SigParseToken(char **input, char *output,
1045 const size_t output_size)
1046 {
1047 size_t len = *input == NULL ? 0 : strlen(*input);
1048
1049 if (!len) {
1050 return 0;
1051 }
1052
1053 while (len && isblank(**input)) {
1054 (*input)++;
1055 len--;
1056 }
1057
1058 char *endptr = strpbrk(*input, " \t\n\r");
1059 if (endptr != NULL) {
1060 *(endptr++) = '\0';
1061 }
1062 strlcpy(output, *input, output_size);
1063 *input = endptr;
1064
1065 return 1;
1066 }
1067
1068 /**
1069 * \brief Parse the next rule "list" token.
1070 *
1071 * Parses rule tokens that may be lists such as addresses and ports
1072 * handling the case when they may not be lists.
1073 *
1074 * \param input double pointer to input buffer, will be advanced as input is
1075 * parsed.
1076 * \param output buffer to copy token into.
1077 * \param output_size length of output buffer.
1078 */
SigParseList(char ** input,char * output,const size_t output_size)1079 static inline int SigParseList(char **input, char *output,
1080 const size_t output_size)
1081 {
1082 int in_list = 0;
1083 size_t len = *input != NULL ? strlen(*input) : 0;
1084
1085 if (len == 0) {
1086 return 0;
1087 }
1088
1089 while (len && isblank(**input)) {
1090 (*input)++;
1091 len--;
1092 }
1093
1094 size_t i = 0;
1095 for (i = 0; i < len; i++) {
1096 char c = (*input)[i];
1097 if (c == '[') {
1098 in_list++;
1099 } else if (c == ']') {
1100 in_list--;
1101 } else if (c == ' ') {
1102 if (!in_list) {
1103 break;
1104 }
1105 }
1106 }
1107 if (i == len) {
1108 *input = NULL;
1109 return 0;
1110 }
1111 (*input)[i] = '\0';
1112 strlcpy(output, *input, output_size);
1113 *input = *input + i + 1;
1114
1115 return 1;
1116 }
1117
1118 /**
1119 * \internal
1120 * \brief split a signature string into a few blocks for further parsing
1121 */
SigParseBasics(DetectEngineCtx * de_ctx,Signature * s,const char * sigstr,SignatureParser * parser,uint8_t addrs_direction)1122 static int SigParseBasics(DetectEngineCtx *de_ctx,
1123 Signature *s, const char *sigstr, SignatureParser *parser, uint8_t addrs_direction)
1124 {
1125 char *index, dup[DETECT_MAX_RULE_SIZE];
1126
1127 strlcpy(dup, sigstr, DETECT_MAX_RULE_SIZE);
1128 index = dup;
1129
1130 /* Action. */
1131 SigParseToken(&index, parser->action, sizeof(parser->action));
1132
1133 /* Protocol. */
1134 SigParseList(&index, parser->protocol, sizeof(parser->protocol));
1135
1136 /* Source. */
1137 SigParseList(&index, parser->src, sizeof(parser->src));
1138
1139 /* Source port(s). */
1140 SigParseList(&index, parser->sp, sizeof(parser->sp));
1141
1142 /* Direction. */
1143 SigParseToken(&index, parser->direction, sizeof(parser->direction));
1144
1145 /* Destination. */
1146 SigParseList(&index, parser->dst, sizeof(parser->dst));
1147
1148 /* Destination port(s). */
1149 SigParseList(&index, parser->dp, sizeof(parser->dp));
1150
1151 /* Options. */
1152 if (index == NULL) {
1153 SCLogError(SC_ERR_INVALID_RULE_ARGUMENT, "no rule options.");
1154 goto error;
1155 }
1156 while (isspace(*index) || *index == '(') {
1157 index++;
1158 }
1159 for (size_t i = strlen(index); i > 0; i--) {
1160 if (isspace(index[i - 1]) || index[i - 1] == ')') {
1161 index[i - 1] = '\0';
1162 } else {
1163 break;
1164 }
1165 }
1166 strlcpy(parser->opts, index, sizeof(parser->opts));
1167
1168 /* Parse Action */
1169 if (SigParseAction(s, parser->action) < 0)
1170 goto error;
1171
1172 if (SigParseProto(s, parser->protocol) < 0)
1173 goto error;
1174
1175 if (strcmp(parser->direction, "<>") == 0) {
1176 s->init_data->init_flags |= SIG_FLAG_INIT_BIDIREC;
1177 } else if (strcmp(parser->direction, "->") != 0) {
1178 SCLogError(SC_ERR_INVALID_DIRECTION,
1179 "\"%s\" is not a valid direction modifier, "
1180 "\"->\" and \"<>\" are supported.", parser->direction);
1181 goto error;
1182 }
1183
1184 /* Parse Address & Ports */
1185 if (SigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ addrs_direction) < 0)
1186 goto error;
1187
1188 if (SigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0)
1189 goto error;
1190
1191 /* By AWS - Traditionally we should be doing this only for tcp/udp/sctp,
1192 * but we do it for regardless of ip proto, since the dns/dnstcp/dnsudp
1193 * changes that we made sees to it that at this point of time we don't
1194 * set the ip proto for the sig. We do it a bit later. */
1195 if (SigParsePort(de_ctx, s, parser->sp, SIG_DIREC_SRC ^ addrs_direction) < 0)
1196 goto error;
1197 if (SigParsePort(de_ctx, s, parser->dp, SIG_DIREC_DST ^ addrs_direction) < 0)
1198 goto error;
1199
1200 return 0;
1201
1202 error:
1203 return -1;
1204 }
1205
1206 /**
1207 * \brief parse a signature
1208 *
1209 * \param de_ctx detection engine ctx to add it to
1210 * \param s memory structure to store the signature in
1211 * \param sigstr the raw signature as a null terminated string
1212 * \param addrs_direction direction (for bi-directional sigs)
1213 *
1214 * \param -1 parse error
1215 * \param 0 ok
1216 */
SigParse(DetectEngineCtx * de_ctx,Signature * s,const char * sigstr,uint8_t addrs_direction,SignatureParser * parser)1217 static int SigParse(DetectEngineCtx *de_ctx, Signature *s,
1218 const char *sigstr, uint8_t addrs_direction, SignatureParser *parser)
1219 {
1220 SCEnter();
1221
1222 if (!rs_check_utf8(sigstr)) {
1223 SCLogError(SC_ERR_RULE_INVALID_UTF8, "rule is not valid UTF-8");
1224 SCReturnInt(-1);
1225 }
1226
1227 s->sig_str = SCStrdup(sigstr);
1228 if (unlikely(s->sig_str == NULL)) {
1229 SCReturnInt(-1);
1230 }
1231
1232 int ret = SigParseBasics(de_ctx, s, sigstr, parser, addrs_direction);
1233 if (ret < 0) {
1234 SCLogDebug("SigParseBasics failed");
1235 SCReturnInt(-1);
1236 }
1237
1238 /* we can have no options, so make sure we have them */
1239 if (strlen(parser->opts) > 0) {
1240 size_t buffer_size = strlen(parser->opts) + 1;
1241 char input[buffer_size];
1242 char output[buffer_size];
1243 memset(input, 0x00, buffer_size);
1244 memcpy(input, parser->opts, strlen(parser->opts)+1);
1245
1246 /* loop the option parsing. Each run processes one option
1247 * and returns the rest of the option string through the
1248 * output variable. */
1249 do {
1250 memset(output, 0x00, buffer_size);
1251 ret = SigParseOptions(de_ctx, s, input, output, buffer_size);
1252 if (ret == 1) {
1253 memcpy(input, output, buffer_size);
1254 }
1255
1256 } while (ret == 1);
1257 }
1258
1259 DetectIPProtoRemoveAllSMs(de_ctx, s);
1260
1261 SCReturnInt(ret);
1262 }
1263
SigAlloc(void)1264 Signature *SigAlloc (void)
1265 {
1266 Signature *sig = SCMalloc(sizeof(Signature));
1267 if (unlikely(sig == NULL))
1268 return NULL;
1269 memset(sig, 0, sizeof(Signature));
1270
1271 sig->init_data = SCCalloc(1, sizeof(SignatureInitData));
1272 if (sig->init_data == NULL) {
1273 SCFree(sig);
1274 return NULL;
1275 }
1276
1277 sig->init_data->smlists_array_size = DetectBufferTypeMaxId();
1278 SCLogDebug("smlists size %u", sig->init_data->smlists_array_size);
1279 sig->init_data->smlists = SCCalloc(sig->init_data->smlists_array_size, sizeof(SigMatch *));
1280 if (sig->init_data->smlists == NULL) {
1281 SCFree(sig->init_data);
1282 SCFree(sig);
1283 return NULL;
1284 }
1285
1286 sig->init_data->smlists_tail = SCCalloc(sig->init_data->smlists_array_size, sizeof(SigMatch *));
1287 if (sig->init_data->smlists_tail == NULL) {
1288 SCFree(sig->init_data->smlists);
1289 SCFree(sig->init_data);
1290 SCFree(sig);
1291 return NULL;
1292 }
1293
1294 /* assign it to -1, so that we can later check if the value has been
1295 * overwritten after the Signature has been parsed, and if it hasn't been
1296 * overwritten, we can then assign the default value of 3 */
1297 sig->prio = -1;
1298
1299 sig->init_data->list = DETECT_SM_LIST_NOTSET;
1300 return sig;
1301 }
1302
1303 /**
1304 * \internal
1305 * \brief Free Metadata list
1306 *
1307 * \param s Pointer to the signature
1308 */
SigMetadataFree(Signature * s)1309 static void SigMetadataFree(Signature *s)
1310 {
1311 SCEnter();
1312
1313 DetectMetadata *mdata = NULL;
1314 DetectMetadata *next_mdata = NULL;
1315
1316 if (s == NULL || s->metadata == NULL) {
1317 SCReturn;
1318 }
1319
1320 SCLogDebug("s %p, s->metadata %p", s, s->metadata);
1321
1322 for (mdata = s->metadata->list; mdata != NULL;) {
1323 next_mdata = mdata->next;
1324 DetectMetadataFree(mdata);
1325 mdata = next_mdata;
1326 }
1327 SCFree(s->metadata->json_str);
1328 SCFree(s->metadata);
1329 s->metadata = NULL;
1330
1331 SCReturn;
1332 }
1333
1334 /**
1335 * \internal
1336 * \brief Free Reference list
1337 *
1338 * \param s Pointer to the signature
1339 */
SigRefFree(Signature * s)1340 static void SigRefFree (Signature *s)
1341 {
1342 SCEnter();
1343
1344 DetectReference *ref = NULL;
1345 DetectReference *next_ref = NULL;
1346
1347 if (s == NULL) {
1348 SCReturn;
1349 }
1350
1351 SCLogDebug("s %p, s->references %p", s, s->references);
1352
1353 for (ref = s->references; ref != NULL;) {
1354 next_ref = ref->next;
1355 DetectReferenceFree(ref);
1356 ref = next_ref;
1357 }
1358
1359 s->references = NULL;
1360
1361 SCReturn;
1362 }
1363
SigMatchFreeArrays(DetectEngineCtx * de_ctx,Signature * s,int ctxs)1364 static void SigMatchFreeArrays(DetectEngineCtx *de_ctx, Signature *s, int ctxs)
1365 {
1366 if (s != NULL) {
1367 int type;
1368 for (type = 0; type < DETECT_SM_LIST_MAX; type++) {
1369 if (s->sm_arrays[type] != NULL) {
1370 if (ctxs) {
1371 SigMatchData *smd = s->sm_arrays[type];
1372 while(1) {
1373 if (sigmatch_table[smd->type].Free != NULL) {
1374 sigmatch_table[smd->type].Free(de_ctx, smd->ctx);
1375 }
1376 if (smd->is_last)
1377 break;
1378 smd++;
1379 }
1380 }
1381
1382 SCFree(s->sm_arrays[type]);
1383 }
1384 }
1385 }
1386 }
1387
SigFree(DetectEngineCtx * de_ctx,Signature * s)1388 void SigFree(DetectEngineCtx *de_ctx, Signature *s)
1389 {
1390 if (s == NULL)
1391 return;
1392
1393 if (s->CidrDst != NULL)
1394 IPOnlyCIDRListFree(s->CidrDst);
1395
1396 if (s->CidrSrc != NULL)
1397 IPOnlyCIDRListFree(s->CidrSrc);
1398
1399 int i;
1400
1401 if (s->init_data && s->init_data->transforms.cnt) {
1402 for(i = 0; i < s->init_data->transforms.cnt; i++) {
1403 if (s->init_data->transforms.transforms[i].options) {
1404 SCFree(s->init_data->transforms.transforms[i].options);
1405 s->init_data->transforms.transforms[i].options = NULL;
1406 }
1407 }
1408 }
1409 if (s->init_data) {
1410 const int nlists = s->init_data->smlists_array_size;
1411 for (i = 0; i < nlists; i++) {
1412 SigMatch *sm = s->init_data->smlists[i];
1413 while (sm != NULL) {
1414 SigMatch *nsm = sm->next;
1415 SigMatchFree(de_ctx, sm);
1416 sm = nsm;
1417 }
1418 }
1419 }
1420 SigMatchFreeArrays(de_ctx, s, (s->init_data == NULL));
1421 if (s->init_data) {
1422 SCFree(s->init_data->smlists);
1423 SCFree(s->init_data->smlists_tail);
1424 SCFree(s->init_data);
1425 s->init_data = NULL;
1426 }
1427
1428 if (s->sp != NULL) {
1429 DetectPortCleanupList(NULL, s->sp);
1430 }
1431 if (s->dp != NULL) {
1432 DetectPortCleanupList(NULL, s->dp);
1433 }
1434
1435 if (s->msg != NULL)
1436 SCFree(s->msg);
1437
1438 if (s->addr_src_match4 != NULL) {
1439 SCFree(s->addr_src_match4);
1440 }
1441 if (s->addr_dst_match4 != NULL) {
1442 SCFree(s->addr_dst_match4);
1443 }
1444 if (s->addr_src_match6 != NULL) {
1445 SCFree(s->addr_src_match6);
1446 }
1447 if (s->addr_dst_match6 != NULL) {
1448 SCFree(s->addr_dst_match6);
1449 }
1450 if (s->sig_str != NULL) {
1451 SCFree(s->sig_str);
1452 }
1453
1454 SigRefFree(s);
1455 SigMetadataFree(s);
1456
1457 DetectEngineAppInspectionEngineSignatureFree(de_ctx, s);
1458
1459 SCFree(s);
1460 }
1461
DetectSignatureAddTransform(Signature * s,int transform,void * options)1462 int DetectSignatureAddTransform(Signature *s, int transform, void *options)
1463 {
1464 /* we only support buffers */
1465 if (s->init_data->list == 0) {
1466 SCReturnInt(-1);
1467 }
1468 if (!s->init_data->list_set) {
1469 SCLogError(SC_ERR_INVALID_SIGNATURE, "transforms must directly follow stickybuffers");
1470 SCReturnInt(-1);
1471 }
1472 if (s->init_data->transforms.cnt >= DETECT_TRANSFORMS_MAX) {
1473 SCReturnInt(-1);
1474 }
1475
1476 s->init_data->transforms.transforms[s->init_data->transforms.cnt].transform = transform;
1477 s->init_data->transforms.transforms[s->init_data->transforms.cnt].options = options;
1478
1479 s->init_data->transforms.cnt++;
1480 SCLogDebug("Added transform #%d [%s]",
1481 s->init_data->transforms.cnt,
1482 s->sig_str);
1483
1484 SCReturnInt(0);
1485 }
1486
DetectSignatureSetAppProto(Signature * s,AppProto alproto)1487 int DetectSignatureSetAppProto(Signature *s, AppProto alproto)
1488 {
1489 if (alproto == ALPROTO_UNKNOWN ||
1490 alproto >= ALPROTO_FAILED) {
1491 SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid alproto %u", alproto);
1492 return -1;
1493 }
1494
1495 if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(alproto, s->alproto)) {
1496 SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS,
1497 "can't set rule app proto to %s: already set to %s",
1498 AppProtoToString(alproto), AppProtoToString(s->alproto));
1499 return -1;
1500 }
1501
1502 // allow to keep HTTP2 as s->alproto with HTTP1 alproto keywords
1503 if (!AppProtoEquals(alproto, s->alproto)) {
1504 s->alproto = alproto;
1505 }
1506 s->flags |= SIG_FLAG_APPLAYER;
1507 return 0;
1508 }
1509
1510 /**
1511 * \internal
1512 * \brief build address match array for cache efficient matching
1513 *
1514 * \param s the signature
1515 */
SigBuildAddressMatchArray(Signature * s)1516 static void SigBuildAddressMatchArray(Signature *s)
1517 {
1518 /* source addresses */
1519 uint16_t cnt = 0;
1520 uint16_t idx = 0;
1521 DetectAddress *da = s->init_data->src->ipv4_head;
1522 for ( ; da != NULL; da = da->next) {
1523 cnt++;
1524 }
1525 if (cnt > 0) {
1526 s->addr_src_match4 = SCMalloc(cnt * sizeof(DetectMatchAddressIPv4));
1527 if (s->addr_src_match4 == NULL) {
1528 exit(EXIT_FAILURE);
1529 }
1530
1531 for (da = s->init_data->src->ipv4_head; da != NULL; da = da->next) {
1532 s->addr_src_match4[idx].ip = SCNtohl(da->ip.addr_data32[0]);
1533 s->addr_src_match4[idx].ip2 = SCNtohl(da->ip2.addr_data32[0]);
1534 idx++;
1535 }
1536 s->addr_src_match4_cnt = cnt;
1537 }
1538
1539 /* destination addresses */
1540 cnt = 0;
1541 idx = 0;
1542 da = s->init_data->dst->ipv4_head;
1543 for ( ; da != NULL; da = da->next) {
1544 cnt++;
1545 }
1546 if (cnt > 0) {
1547 s->addr_dst_match4 = SCMalloc(cnt * sizeof(DetectMatchAddressIPv4));
1548 if (s->addr_dst_match4 == NULL) {
1549 exit(EXIT_FAILURE);
1550 }
1551
1552 for (da = s->init_data->dst->ipv4_head; da != NULL; da = da->next) {
1553 s->addr_dst_match4[idx].ip = SCNtohl(da->ip.addr_data32[0]);
1554 s->addr_dst_match4[idx].ip2 = SCNtohl(da->ip2.addr_data32[0]);
1555 idx++;
1556 }
1557 s->addr_dst_match4_cnt = cnt;
1558 }
1559
1560 /* source addresses IPv6 */
1561 cnt = 0;
1562 idx = 0;
1563 da = s->init_data->src->ipv6_head;
1564 for ( ; da != NULL; da = da->next) {
1565 cnt++;
1566 }
1567 if (cnt > 0) {
1568 s->addr_src_match6 = SCMalloc(cnt * sizeof(DetectMatchAddressIPv6));
1569 if (s->addr_src_match6 == NULL) {
1570 exit(EXIT_FAILURE);
1571 }
1572
1573 for (da = s->init_data->src->ipv6_head; da != NULL; da = da->next) {
1574 s->addr_src_match6[idx].ip[0] = SCNtohl(da->ip.addr_data32[0]);
1575 s->addr_src_match6[idx].ip[1] = SCNtohl(da->ip.addr_data32[1]);
1576 s->addr_src_match6[idx].ip[2] = SCNtohl(da->ip.addr_data32[2]);
1577 s->addr_src_match6[idx].ip[3] = SCNtohl(da->ip.addr_data32[3]);
1578 s->addr_src_match6[idx].ip2[0] = SCNtohl(da->ip2.addr_data32[0]);
1579 s->addr_src_match6[idx].ip2[1] = SCNtohl(da->ip2.addr_data32[1]);
1580 s->addr_src_match6[idx].ip2[2] = SCNtohl(da->ip2.addr_data32[2]);
1581 s->addr_src_match6[idx].ip2[3] = SCNtohl(da->ip2.addr_data32[3]);
1582 idx++;
1583 }
1584 s->addr_src_match6_cnt = cnt;
1585 }
1586
1587 /* destination addresses IPv6 */
1588 cnt = 0;
1589 idx = 0;
1590 da = s->init_data->dst->ipv6_head;
1591 for ( ; da != NULL; da = da->next) {
1592 cnt++;
1593 }
1594 if (cnt > 0) {
1595 s->addr_dst_match6 = SCMalloc(cnt * sizeof(DetectMatchAddressIPv6));
1596 if (s->addr_dst_match6 == NULL) {
1597 exit(EXIT_FAILURE);
1598 }
1599
1600 for (da = s->init_data->dst->ipv6_head; da != NULL; da = da->next) {
1601 s->addr_dst_match6[idx].ip[0] = SCNtohl(da->ip.addr_data32[0]);
1602 s->addr_dst_match6[idx].ip[1] = SCNtohl(da->ip.addr_data32[1]);
1603 s->addr_dst_match6[idx].ip[2] = SCNtohl(da->ip.addr_data32[2]);
1604 s->addr_dst_match6[idx].ip[3] = SCNtohl(da->ip.addr_data32[3]);
1605 s->addr_dst_match6[idx].ip2[0] = SCNtohl(da->ip2.addr_data32[0]);
1606 s->addr_dst_match6[idx].ip2[1] = SCNtohl(da->ip2.addr_data32[1]);
1607 s->addr_dst_match6[idx].ip2[2] = SCNtohl(da->ip2.addr_data32[2]);
1608 s->addr_dst_match6[idx].ip2[3] = SCNtohl(da->ip2.addr_data32[3]);
1609 idx++;
1610 }
1611 s->addr_dst_match6_cnt = cnt;
1612 }
1613 }
1614
SigMatchListLen(SigMatch * sm)1615 static int SigMatchListLen(SigMatch *sm)
1616 {
1617 int len = 0;
1618 for (; sm != NULL; sm = sm->next)
1619 len++;
1620
1621 return len;
1622 }
1623
1624 /** \brief convert SigMatch list to SigMatchData array
1625 * \note ownership of sm->ctx is transferred to smd->ctx
1626 */
SigMatchList2DataArray(SigMatch * head)1627 SigMatchData* SigMatchList2DataArray(SigMatch *head)
1628 {
1629 int len = SigMatchListLen(head);
1630 if (len == 0)
1631 return NULL;
1632
1633 SigMatchData *smd = (SigMatchData *)SCCalloc(len, sizeof(SigMatchData));
1634 if (smd == NULL) {
1635 FatalError(SC_ERR_FATAL, "initializing the detection engine failed");
1636 }
1637 SigMatchData *out = smd;
1638
1639 /* Copy sm type and Context into array */
1640 SigMatch *sm = head;
1641 for (; sm != NULL; sm = sm->next, smd++) {
1642 smd->type = sm->type;
1643 smd->ctx = sm->ctx;
1644 sm->ctx = NULL; // SigMatch no longer owns the ctx
1645 smd->is_last = (sm->next == NULL);
1646 }
1647 return out;
1648 }
1649
1650 /**
1651 * \internal
1652 * \brief validate a just parsed signature for internal inconsistencies
1653 *
1654 * \param s just parsed signature
1655 *
1656 * \retval 0 invalid
1657 * \retval 1 valid
1658 */
SigValidate(DetectEngineCtx * de_ctx,Signature * s)1659 static int SigValidate(DetectEngineCtx *de_ctx, Signature *s)
1660 {
1661 uint32_t sig_flags = 0;
1662 SigMatch *sm;
1663 const int nlists = s->init_data->smlists_array_size;
1664
1665 SCEnter();
1666
1667 /* check for sticky buffers that were set w/o matches
1668 * e.g. alert ... (file_data; sid:1;) */
1669 if (s->init_data->list != DETECT_SM_LIST_NOTSET) {
1670 if (s->init_data->smlists[s->init_data->list] == NULL) {
1671 SCLogError(SC_ERR_INVALID_SIGNATURE, "rule %u setup buffer %s but didn't add matches to it",
1672 s->id, DetectBufferTypeGetNameById(de_ctx, s->init_data->list));
1673 SCReturnInt(0);
1674 }
1675 }
1676
1677 /* run buffer type validation callbacks if any */
1678 if (s->init_data->smlists[DETECT_SM_LIST_PMATCH]) {
1679 if (DetectContentPMATCHValidateCallback(s) == FALSE)
1680 SCReturnInt(0);
1681 }
1682
1683 struct BufferVsDir {
1684 int ts;
1685 int tc;
1686 } bufdir[nlists];
1687 memset(&bufdir, 0, nlists * sizeof(struct BufferVsDir));
1688
1689 int x;
1690 for (x = 0; x < nlists; x++) {
1691 if (s->init_data->smlists[x]) {
1692 const DetectEngineAppInspectionEngine *app = de_ctx->app_inspect_engines;
1693 for ( ; app != NULL; app = app->next) {
1694 if (app->sm_list == x &&
1695 (AppProtoEquals(s->alproto, app->alproto) || s->alproto == 0)) {
1696 SCLogDebug("engine %s dir %d alproto %d",
1697 DetectBufferTypeGetNameById(de_ctx, app->sm_list),
1698 app->dir, app->alproto);
1699
1700 bufdir[x].ts += (app->dir == 0);
1701 bufdir[x].tc += (app->dir == 1);
1702 }
1703 }
1704
1705 if (DetectBufferRunValidateCallback(de_ctx, x, s, &de_ctx->sigerror) == FALSE) {
1706 SCReturnInt(0);
1707 }
1708 }
1709 }
1710
1711 int ts_excl = 0;
1712 int tc_excl = 0;
1713 int dir_amb = 0;
1714 for (x = 0; x < nlists; x++) {
1715 if (bufdir[x].ts == 0 && bufdir[x].tc == 0)
1716 continue;
1717 ts_excl += (bufdir[x].ts > 0 && bufdir[x].tc == 0);
1718 tc_excl += (bufdir[x].ts == 0 && bufdir[x].tc > 0);
1719 dir_amb += (bufdir[x].ts > 0 && bufdir[x].tc > 0);
1720
1721 SCLogDebug("%s/%d: %d/%d", DetectBufferTypeGetNameById(de_ctx, x),
1722 x, bufdir[x].ts, bufdir[x].tc);
1723 }
1724 if (ts_excl && tc_excl) {
1725 SCLogError(SC_ERR_INVALID_SIGNATURE, "rule %u mixes keywords with conflicting directions", s->id);
1726 SCReturnInt(0);
1727 } else if (ts_excl) {
1728 SCLogDebug("%u: implied rule direction is toserver", s->id);
1729 if (DetectFlowSetupImplicit(s, SIG_FLAG_TOSERVER) < 0) {
1730 SCLogError(SC_ERR_INVALID_SIGNATURE, "rule %u mixes keywords with conflicting directions", s->id);
1731 SCReturnInt(0);
1732 }
1733 } else if (tc_excl) {
1734 SCLogDebug("%u: implied rule direction is toclient", s->id);
1735 if (DetectFlowSetupImplicit(s, SIG_FLAG_TOCLIENT) < 0) {
1736 SCLogError(SC_ERR_INVALID_SIGNATURE, "rule %u mixes keywords with conflicting directions", s->id);
1737 SCReturnInt(0);
1738 }
1739 } else if (dir_amb) {
1740 SCLogDebug("%u: rule direction cannot be deduced from keywords", s->id);
1741 }
1742
1743 if ((s->flags & SIG_FLAG_REQUIRE_PACKET) &&
1744 (s->flags & SIG_FLAG_REQUIRE_STREAM)) {
1745 SCLogError(SC_ERR_INVALID_SIGNATURE, "can't mix packet keywords with "
1746 "tcp-stream or flow:only_stream. Invalidating signature.");
1747 SCReturnInt(0);
1748 }
1749
1750 #if 0 // TODO figure out why this is even necessary
1751 if ((s->init_data->smlists[DETECT_SM_LIST_FILEDATA] != NULL && s->alproto == ALPROTO_SMTP) ||
1752 s->init_data->smlists[DETECT_SM_LIST_UMATCH] != NULL ||
1753 s->init_data->smlists[DETECT_SM_LIST_HRUDMATCH] != NULL ||
1754 s->init_data->smlists[DETECT_SM_LIST_HCBDMATCH] != NULL ||
1755 s->init_data->smlists[DETECT_SM_LIST_HUADMATCH] != NULL) {
1756 sig_flags |= SIG_FLAG_TOSERVER;
1757 s->flags |= SIG_FLAG_TOSERVER;
1758 s->flags &= ~SIG_FLAG_TOCLIENT;
1759 }
1760 if ((s->init_data->smlists[DETECT_SM_LIST_FILEDATA] != NULL && s->alproto == ALPROTO_HTTP) ||
1761 s->init_data->smlists[DETECT_SM_LIST_HSMDMATCH] != NULL ||
1762 s->init_data->smlists[DETECT_SM_LIST_HSCDMATCH] != NULL) {
1763 sig_flags |= SIG_FLAG_TOCLIENT;
1764 s->flags |= SIG_FLAG_TOCLIENT;
1765 s->flags &= ~SIG_FLAG_TOSERVER;
1766 }
1767 #endif
1768 if ((sig_flags & (SIG_FLAG_TOCLIENT | SIG_FLAG_TOSERVER)) == (SIG_FLAG_TOCLIENT | SIG_FLAG_TOSERVER)) {
1769 SCLogError(SC_ERR_INVALID_SIGNATURE,"You seem to have mixed keywords "
1770 "that require inspection in both directions. Atm we only "
1771 "support keywords in one direction within a rule.");
1772 SCReturnInt(0);
1773 }
1774
1775 if (s->flags & SIG_FLAG_REQUIRE_PACKET) {
1776 for (int i = 0; i < nlists; i++) {
1777 if (s->init_data->smlists[i] == NULL)
1778 continue;
1779 if (!(DetectBufferTypeGetNameById(de_ctx, i)))
1780 continue;
1781
1782 if (!(DetectBufferTypeSupportsPacketGetById(de_ctx, i))) {
1783 SCLogError(SC_ERR_INVALID_SIGNATURE, "Signature combines packet "
1784 "specific matches (like dsize, flags, ttl) with stream / "
1785 "state matching by matching on app layer proto (like using "
1786 "http_* keywords).");
1787 SCReturnInt(0);
1788 }
1789 }
1790 }
1791
1792 /* TCP: corner cases:
1793 * - pkt vs stream vs depth/offset
1794 * - pkt vs stream vs stream_size
1795 */
1796 if (s->proto.proto[IPPROTO_TCP / 8] & (1 << (IPPROTO_TCP % 8))) {
1797 if (s->init_data->smlists[DETECT_SM_LIST_PMATCH]) {
1798 if (!(s->flags & (SIG_FLAG_REQUIRE_PACKET | SIG_FLAG_REQUIRE_STREAM))) {
1799 s->flags |= SIG_FLAG_REQUIRE_STREAM;
1800 sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH];
1801 while (sm != NULL) {
1802 if (sm->type == DETECT_CONTENT &&
1803 (((DetectContentData *)(sm->ctx))->flags &
1804 (DETECT_CONTENT_DEPTH | DETECT_CONTENT_OFFSET))) {
1805 s->flags |= SIG_FLAG_REQUIRE_PACKET;
1806 break;
1807 }
1808 sm = sm->next;
1809 }
1810 /* if stream_size is in use, also inspect packets */
1811 sm = s->init_data->smlists[DETECT_SM_LIST_MATCH];
1812 while (sm != NULL) {
1813 if (sm->type == DETECT_STREAM_SIZE) {
1814 s->flags |= SIG_FLAG_REQUIRE_PACKET;
1815 break;
1816 }
1817 sm = sm->next;
1818 }
1819 }
1820 }
1821 }
1822
1823 if (s->init_data->smlists[DETECT_SM_LIST_BASE64_DATA] != NULL) {
1824 int list;
1825 uint16_t idx = s->init_data->smlists[DETECT_SM_LIST_BASE64_DATA]->idx;
1826 for (list = 0; list < nlists; list++) {
1827 if (list == DETECT_SM_LIST_POSTMATCH ||
1828 list == DETECT_SM_LIST_TMATCH ||
1829 list == DETECT_SM_LIST_SUPPRESS ||
1830 list == DETECT_SM_LIST_THRESHOLD)
1831 {
1832 continue;
1833 }
1834
1835 if (list != DETECT_SM_LIST_BASE64_DATA &&
1836 s->init_data->smlists[list] != NULL) {
1837 if (s->init_data->smlists[list]->idx > idx) {
1838 SCLogError(SC_ERR_INVALID_SIGNATURE, "Rule buffer "
1839 "cannot be reset after base64_data.");
1840 SCReturnInt(0);
1841 }
1842 }
1843 }
1844 }
1845
1846 #ifdef HAVE_LUA
1847 DetectLuaPostSetup(s);
1848 #endif
1849
1850 #ifdef DEBUG
1851 int i;
1852 for (i = 0; i < nlists; i++) {
1853 if (s->init_data->smlists[i] != NULL) {
1854 for (sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
1855 BUG_ON(sm == sm->prev);
1856 BUG_ON(sm == sm->next);
1857 }
1858 }
1859 }
1860 #endif
1861
1862 if ((s->flags & SIG_FLAG_FILESTORE) || s->file_flags != 0 ||
1863 (s->init_data->init_flags & SIG_FLAG_INIT_FILEDATA)) {
1864 if (s->alproto != ALPROTO_UNKNOWN &&
1865 !AppLayerParserSupportsFiles(IPPROTO_TCP, s->alproto))
1866 {
1867 SCLogError(SC_ERR_NO_FILES_FOR_PROTOCOL, "protocol %s doesn't "
1868 "support file matching", AppProtoToString(s->alproto));
1869 SCReturnInt(0);
1870 }
1871 if (s->alproto == ALPROTO_HTTP2 && (s->file_flags & FILE_SIG_NEED_FILENAME)) {
1872 SCLogError(SC_ERR_NO_FILES_FOR_PROTOCOL,
1873 "protocol HTTP2 doesn't support file name matching");
1874 SCReturnInt(0);
1875 }
1876
1877 if (s->alproto == ALPROTO_HTTP) {
1878 AppLayerHtpNeedFileInspection();
1879 }
1880 }
1881 if (s->init_data->init_flags & SIG_FLAG_INIT_DCERPC) {
1882 if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_DCERPC &&
1883 s->alproto != ALPROTO_SMB) {
1884 SCLogError(SC_ERR_NO_FILES_FOR_PROTOCOL, "protocol %s doesn't support DCERPC keyword",
1885 AppProtoToString(s->alproto));
1886 SCReturnInt(0);
1887 }
1888 }
1889 SCReturnInt(1);
1890 }
1891
1892 /**
1893 * \internal
1894 * \brief Helper function for SigInit().
1895 */
SigInitHelper(DetectEngineCtx * de_ctx,const char * sigstr,uint8_t dir)1896 static Signature *SigInitHelper(DetectEngineCtx *de_ctx, const char *sigstr,
1897 uint8_t dir)
1898 {
1899 SignatureParser parser;
1900 memset(&parser, 0x00, sizeof(parser));
1901
1902 Signature *sig = SigAlloc();
1903 if (sig == NULL)
1904 goto error;
1905
1906 /* default gid to 1 */
1907 sig->gid = 1;
1908
1909 int ret = SigParse(de_ctx, sig, sigstr, dir, &parser);
1910 if (ret == -3) {
1911 de_ctx->sigerror_silent = true;
1912 de_ctx->sigerror_ok = true;
1913 goto error;
1914 }
1915 else if (ret == -2) {
1916 de_ctx->sigerror_silent = true;
1917 goto error;
1918 } else if (ret < 0) {
1919 goto error;
1920 }
1921
1922 /* signature priority hasn't been overwritten. Using default priority */
1923 if (sig->prio == -1)
1924 sig->prio = DETECT_DEFAULT_PRIO;
1925
1926 sig->num = de_ctx->signum;
1927 de_ctx->signum++;
1928
1929 if (sig->alproto != ALPROTO_UNKNOWN) {
1930 int override_needed = 0;
1931 if (sig->proto.flags & DETECT_PROTO_ANY) {
1932 sig->proto.flags &= ~DETECT_PROTO_ANY;
1933 memset(sig->proto.proto, 0x00, sizeof(sig->proto.proto));
1934 override_needed = 1;
1935 } else {
1936 override_needed = 1;
1937 size_t s = 0;
1938 for (s = 0; s < sizeof(sig->proto.proto); s++) {
1939 if (sig->proto.proto[s] != 0x00) {
1940 override_needed = 0;
1941 break;
1942 }
1943 }
1944 }
1945
1946 /* at this point if we had alert ip and the ip proto was not
1947 * overridden, we use the ip proto that has been configured
1948 * against the app proto in use. */
1949 if (override_needed)
1950 AppLayerProtoDetectSupportedIpprotos(sig->alproto, sig->proto.proto);
1951 }
1952
1953 ret = DetectAppLayerEventPrepare(de_ctx, sig);
1954 if (ret == -3) {
1955 de_ctx->sigerror_silent = true;
1956 de_ctx->sigerror_ok = true;
1957 goto error;
1958 }
1959 else if (ret == -2) {
1960 de_ctx->sigerror_silent = true;
1961 goto error;
1962 } else if (ret < 0) {
1963 goto error;
1964 }
1965
1966 /* set the packet and app layer flags, but only if the
1967 * app layer flag wasn't already set in which case we
1968 * only consider the app layer */
1969 if (!(sig->flags & SIG_FLAG_APPLAYER)) {
1970 if (sig->init_data->smlists[DETECT_SM_LIST_MATCH] != NULL) {
1971 SigMatch *sm = sig->init_data->smlists[DETECT_SM_LIST_MATCH];
1972 for ( ; sm != NULL; sm = sm->next) {
1973 if (sigmatch_table[sm->type].Match != NULL)
1974 sig->init_data->init_flags |= SIG_FLAG_INIT_PACKET;
1975 }
1976 } else {
1977 sig->init_data->init_flags |= SIG_FLAG_INIT_PACKET;
1978 }
1979 }
1980
1981 if (!(sig->init_data->init_flags & SIG_FLAG_INIT_FLOW)) {
1982 if ((sig->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) {
1983 sig->flags |= SIG_FLAG_TOSERVER;
1984 sig->flags |= SIG_FLAG_TOCLIENT;
1985 }
1986 }
1987
1988 SCLogDebug("sig %"PRIu32" SIG_FLAG_APPLAYER: %s, SIG_FLAG_PACKET: %s",
1989 sig->id, sig->flags & SIG_FLAG_APPLAYER ? "set" : "not set",
1990 sig->init_data->init_flags & SIG_FLAG_INIT_PACKET ? "set" : "not set");
1991
1992 SigBuildAddressMatchArray(sig);
1993
1994 /* run buffer type callbacks if any */
1995 for (uint32_t x = 0; x < sig->init_data->smlists_array_size; x++) {
1996 if (sig->init_data->smlists[x])
1997 DetectBufferRunSetupCallback(de_ctx, x, sig);
1998 }
1999
2000 /* validate signature, SigValidate will report the error reason */
2001 if (SigValidate(de_ctx, sig) == 0) {
2002 goto error;
2003 }
2004
2005 /* check what the type of this sig is */
2006 SignatureSetType(de_ctx, sig);
2007
2008 if (sig->flags & SIG_FLAG_IPONLY) {
2009 /* For IPOnly */
2010 if (IPOnlySigParseAddress(de_ctx, sig, parser.src, SIG_DIREC_SRC ^ dir) < 0)
2011 goto error;
2012
2013 if (IPOnlySigParseAddress(de_ctx, sig, parser.dst, SIG_DIREC_DST ^ dir) < 0)
2014 goto error;
2015 }
2016 return sig;
2017
2018 error:
2019 if (sig != NULL) {
2020 SigFree(de_ctx, sig);
2021 }
2022 return NULL;
2023 }
2024
2025 /**
2026 * \brief Checks if a signature has the same source and destination
2027 * \param s parsed signature
2028 *
2029 * \retval true if source and destination are the same, false otherwise
2030 */
SigHasSameSourceAndDestination(const Signature * s)2031 static bool SigHasSameSourceAndDestination(const Signature *s)
2032 {
2033 if (!(s->flags & SIG_FLAG_SP_ANY) || !(s->flags & SIG_FLAG_DP_ANY)) {
2034 if (!DetectPortListsAreEqual(s->sp, s->dp)) {
2035 return false;
2036 }
2037 }
2038
2039 if (!(s->flags & SIG_FLAG_SRC_ANY) || !(s->flags & SIG_FLAG_DST_ANY)) {
2040 DetectAddress *src = s->init_data->src->ipv4_head;
2041 DetectAddress *dst = s->init_data->dst->ipv4_head;
2042
2043 if (!DetectAddressListsAreEqual(src, dst)) {
2044 return false;
2045 }
2046
2047 src = s->init_data->src->ipv6_head;
2048 dst = s->init_data->dst->ipv6_head;
2049
2050 if (!DetectAddressListsAreEqual(src, dst)) {
2051 return false;
2052 }
2053 }
2054
2055 return true;
2056 }
2057
2058 /**
2059 * \brief Parses a signature and adds it to the Detection Engine Context.
2060 *
2061 * \param de_ctx Pointer to the Detection Engine Context.
2062 * \param sigstr Pointer to a character string containing the signature to be
2063 * parsed.
2064 *
2065 * \retval Pointer to the Signature instance on success; NULL on failure.
2066 */
SigInit(DetectEngineCtx * de_ctx,const char * sigstr)2067 Signature *SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
2068 {
2069 SCEnter();
2070
2071 uint32_t oldsignum = de_ctx->signum;
2072 de_ctx->sigerror_silent = false;
2073
2074 Signature *sig;
2075
2076 if ((sig = SigInitHelper(de_ctx, sigstr, SIG_DIREC_NORMAL)) == NULL) {
2077 goto error;
2078 }
2079
2080 if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
2081 if (SigHasSameSourceAndDestination(sig)) {
2082 SCLogInfo("Rule with ID %u is bidirectional, but source and destination are the same, "
2083 "treating the rule as unidirectional", sig->id);
2084
2085 sig->init_data->init_flags &= ~SIG_FLAG_INIT_BIDIREC;
2086 } else {
2087 sig->next = SigInitHelper(de_ctx, sigstr, SIG_DIREC_SWITCHED);
2088 if (sig->next == NULL) {
2089 goto error;
2090 }
2091 }
2092 }
2093
2094 SCReturnPtr(sig, "Signature");
2095
2096 error:
2097 if (sig != NULL) {
2098 SigFree(de_ctx, sig);
2099 }
2100 /* if something failed, restore the old signum count
2101 * since we didn't install it */
2102 de_ctx->signum = oldsignum;
2103
2104 SCReturnPtr(NULL, "Signature");
2105 }
2106
2107 /**
2108 * \brief The hash free function to be the used by the hash table -
2109 * DetectEngineCtx->dup_sig_hash_table.
2110 *
2111 * \param data Pointer to the data, in our case SigDuplWrapper to be freed.
2112 */
DetectParseDupSigFreeFunc(void * data)2113 static void DetectParseDupSigFreeFunc(void *data)
2114 {
2115 if (data != NULL)
2116 SCFree(data);
2117
2118 return;
2119 }
2120
2121 /**
2122 * \brief The hash function to be the used by the hash table -
2123 * DetectEngineCtx->dup_sig_hash_table.
2124 *
2125 * \param ht Pointer to the hash table.
2126 * \param data Pointer to the data, in our case SigDuplWrapper.
2127 * \param datalen Not used in our case.
2128 *
2129 * \retval sw->s->id The generated hash value.
2130 */
DetectParseDupSigHashFunc(HashListTable * ht,void * data,uint16_t datalen)2131 static uint32_t DetectParseDupSigHashFunc(HashListTable *ht, void *data, uint16_t datalen)
2132 {
2133 SigDuplWrapper *sw = (SigDuplWrapper *)data;
2134
2135 return (sw->s->id % ht->array_size);
2136 }
2137
2138 /**
2139 * \brief The Compare function to be used by the hash table -
2140 * DetectEngineCtx->dup_sig_hash_table.
2141 *
2142 * \param data1 Pointer to the first SigDuplWrapper.
2143 * \param len1 Not used.
2144 * \param data2 Pointer to the second SigDuplWrapper.
2145 * \param len2 Not used.
2146 *
2147 * \retval 1 If the 2 SigDuplWrappers sent as args match.
2148 * \retval 0 If the 2 SigDuplWrappers sent as args do not match.
2149 */
DetectParseDupSigCompareFunc(void * data1,uint16_t len1,void * data2,uint16_t len2)2150 static char DetectParseDupSigCompareFunc(void *data1, uint16_t len1, void *data2,
2151 uint16_t len2)
2152 {
2153 SigDuplWrapper *sw1 = (SigDuplWrapper *)data1;
2154 SigDuplWrapper *sw2 = (SigDuplWrapper *)data2;
2155
2156 if (sw1 == NULL || sw2 == NULL ||
2157 sw1->s == NULL || sw2->s == NULL)
2158 return 0;
2159
2160 /* sid and gid match required */
2161 if (sw1->s->id == sw2->s->id && sw1->s->gid == sw2->s->gid) return 1;
2162
2163 return 0;
2164 }
2165
2166 /**
2167 * \brief Initializes the hash table that is used to cull duplicate sigs.
2168 *
2169 * \param de_ctx Pointer to the detection engine context.
2170 *
2171 * \retval 0 On success.
2172 * \retval -1 On failure.
2173 */
DetectParseDupSigHashInit(DetectEngineCtx * de_ctx)2174 int DetectParseDupSigHashInit(DetectEngineCtx *de_ctx)
2175 {
2176 de_ctx->dup_sig_hash_table = HashListTableInit(15000,
2177 DetectParseDupSigHashFunc,
2178 DetectParseDupSigCompareFunc,
2179 DetectParseDupSigFreeFunc);
2180 if (de_ctx->dup_sig_hash_table == NULL)
2181 return -1;
2182
2183 return 0;
2184 }
2185
2186 /**
2187 * \brief Frees the hash table that is used to cull duplicate sigs.
2188 *
2189 * \param de_ctx Pointer to the detection engine context that holds this table.
2190 */
DetectParseDupSigHashFree(DetectEngineCtx * de_ctx)2191 void DetectParseDupSigHashFree(DetectEngineCtx *de_ctx)
2192 {
2193 if (de_ctx->dup_sig_hash_table != NULL)
2194 HashListTableFree(de_ctx->dup_sig_hash_table);
2195
2196 de_ctx->dup_sig_hash_table = NULL;
2197
2198 return;
2199 }
2200
2201 /**
2202 * \brief Check if a signature is a duplicate.
2203 *
2204 * There are 3 types of return values for this function.
2205 *
2206 * - 0, which indicates that the Signature is not a duplicate
2207 * and has to be added to the detection engine list.
2208 * - 1, Signature is duplicate, and the existing signature in
2209 * the list shouldn't be replaced with this duplicate.
2210 * - 2, Signature is duplicate, and the existing signature in
2211 * the list should be replaced with this duplicate.
2212 *
2213 * \param de_ctx Pointer to the detection engine context.
2214 * \param sig Pointer to the Signature that has to be checked.
2215 *
2216 * \retval 2 If Signature is duplicate and the existing signature in
2217 * the list should be chucked out and replaced with this.
2218 * \retval 1 If Signature is duplicate, and should be chucked out.
2219 * \retval 0 If Signature is not a duplicate.
2220 */
DetectEngineSignatureIsDuplicate(DetectEngineCtx * de_ctx,Signature * sig)2221 static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx,
2222 Signature *sig)
2223 {
2224 /* we won't do any NULL checks on the args */
2225
2226 /* return value */
2227 int ret = 0;
2228
2229 SigDuplWrapper *sw_dup = NULL;
2230 SigDuplWrapper *sw = NULL;
2231
2232 /* used for making a duplicate_sig_hash_table entry */
2233 sw = SCMalloc(sizeof(SigDuplWrapper));
2234 if (unlikely(sw == NULL)) {
2235 exit(EXIT_FAILURE);
2236 }
2237 memset(sw, 0, sizeof(SigDuplWrapper));
2238 sw->s = sig;
2239
2240 /* check if we have a duplicate entry for this signature */
2241 sw_dup = HashListTableLookup(de_ctx->dup_sig_hash_table, (void *)sw, 0);
2242 /* we don't have a duplicate entry for this sig */
2243 if (sw_dup == NULL) {
2244 /* add it to the hash table */
2245 HashListTableAdd(de_ctx->dup_sig_hash_table, (void *)sw, 0);
2246
2247 /* add the s_prev entry for the previously loaded sw in the hash_table */
2248 if (de_ctx->sig_list != NULL) {
2249 SigDuplWrapper *sw_old = NULL;
2250 SigDuplWrapper sw_tmp;
2251 memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
2252
2253 /* the topmost sig would be the last loaded sig */
2254 sw_tmp.s = de_ctx->sig_list;
2255 sw_old = HashListTableLookup(de_ctx->dup_sig_hash_table,
2256 (void *)&sw_tmp, 0);
2257 /* sw_old == NULL case is impossible */
2258 sw_old->s_prev = sig;
2259 }
2260
2261 ret = 0;
2262 goto end;
2263 }
2264
2265 /* if we have reached here we have a duplicate entry for this signature.
2266 * Check the signature revision. Store the signature with the latest rev
2267 * and discard the other one */
2268 if (sw->s->rev <= sw_dup->s->rev) {
2269 ret = 1;
2270 SCFree(sw);
2271 sw = NULL;
2272 goto end;
2273 }
2274
2275 /* the new sig is of a newer revision than the one that is already in the
2276 * list. Remove the old sig from the list */
2277 if (sw_dup->s_prev == NULL) {
2278 SigDuplWrapper sw_temp;
2279 memset(&sw_temp, 0, sizeof(SigDuplWrapper));
2280 if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
2281 sw_temp.s = sw_dup->s->next->next;
2282 de_ctx->sig_list = sw_dup->s->next->next;
2283 SigFree(de_ctx, sw_dup->s->next);
2284 } else {
2285 sw_temp.s = sw_dup->s->next;
2286 de_ctx->sig_list = sw_dup->s->next;
2287 }
2288 SigDuplWrapper *sw_next = NULL;
2289 if (sw_temp.s != NULL) {
2290 sw_next = HashListTableLookup(de_ctx->dup_sig_hash_table,
2291 (void *)&sw_temp, 0);
2292 sw_next->s_prev = sw_dup->s_prev;
2293 }
2294 SigFree(de_ctx, sw_dup->s);
2295 } else {
2296 SigDuplWrapper sw_temp;
2297 memset(&sw_temp, 0, sizeof(SigDuplWrapper));
2298 if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
2299 sw_temp.s = sw_dup->s->next->next;
2300 /* If previous signature is bidirectional,
2301 * it has 2 items in the linked list.
2302 * So we need to change next->next instead of next
2303 */
2304 if (sw_dup->s_prev->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
2305 sw_dup->s_prev->next->next = sw_dup->s->next->next;
2306 } else {
2307 sw_dup->s_prev->next = sw_dup->s->next->next;
2308 }
2309 SigFree(de_ctx, sw_dup->s->next);
2310 } else {
2311 sw_temp.s = sw_dup->s->next;
2312 if (sw_dup->s_prev->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
2313 sw_dup->s_prev->next->next = sw_dup->s->next;
2314 } else {
2315 sw_dup->s_prev->next = sw_dup->s->next;
2316 }
2317 }
2318 SigDuplWrapper *sw_next = NULL;
2319 if (sw_temp.s != NULL) {
2320 sw_next = HashListTableLookup(de_ctx->dup_sig_hash_table,
2321 (void *)&sw_temp, 0);
2322 sw_next->s_prev = sw_dup->s_prev;;
2323 }
2324 SigFree(de_ctx, sw_dup->s);
2325 }
2326
2327 /* make changes to the entry to reflect the presence of the new sig */
2328 sw_dup->s = sig;
2329 sw_dup->s_prev = NULL;
2330
2331 if (de_ctx->sig_list != NULL) {
2332 SigDuplWrapper sw_tmp;
2333 memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
2334 sw_tmp.s = de_ctx->sig_list;
2335 SigDuplWrapper *sw_old = HashListTableLookup(de_ctx->dup_sig_hash_table,
2336 (void *)&sw_tmp, 0);
2337 if (sw_old->s != sw_dup->s) {
2338 // Link on top of the list if there was another element
2339 sw_old->s_prev = sig;
2340 }
2341 }
2342
2343 /* this is duplicate, but a duplicate that replaced the existing sig entry */
2344 ret = 2;
2345
2346 SCFree(sw);
2347
2348 end:
2349 return ret;
2350 }
2351
2352 /**
2353 * \brief Parse and append a Signature into the Detection Engine Context
2354 * signature list.
2355 *
2356 * If the signature is bidirectional it should append two signatures
2357 * (with the addresses switched) into the list. Also handle duplicate
2358 * signatures. In case of duplicate sigs, use the ones that have the
2359 * latest revision. We use the sid and the msg to identify duplicate
2360 * sigs. If 2 sigs have the same sid and gid, they are duplicates.
2361 *
2362 * \param de_ctx Pointer to the Detection Engine Context.
2363 * \param sigstr Pointer to a character string containing the signature to be
2364 * parsed.
2365 * \param sig_file Pointer to a character string containing the filename from
2366 * which signature is read
2367 * \param lineno Line number from where signature is read
2368 *
2369 * \retval Pointer to the head Signature in the detection engine ctx sig_list
2370 * on success; NULL on failure.
2371 */
DetectEngineAppendSig(DetectEngineCtx * de_ctx,const char * sigstr)2372 Signature *DetectEngineAppendSig(DetectEngineCtx *de_ctx, const char *sigstr)
2373 {
2374 Signature *sig = SigInit(de_ctx, sigstr);
2375 if (sig == NULL) {
2376 return NULL;
2377 }
2378
2379 /* checking for the status of duplicate signature */
2380 int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig);
2381 /* a duplicate signature that should be chucked out. Check the previously
2382 * called function details to understand the different return values */
2383 if (dup_sig == 1) {
2384 SCLogError(SC_ERR_DUPLICATE_SIG, "Duplicate signature \"%s\"", sigstr);
2385 goto error;
2386 } else if (dup_sig == 2) {
2387 SCLogWarning(SC_ERR_DUPLICATE_SIG, "Signature with newer revision,"
2388 " so the older sig replaced by this new signature \"%s\"",
2389 sigstr);
2390 }
2391
2392 if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
2393 if (sig->next != NULL) {
2394 sig->next->next = de_ctx->sig_list;
2395 } else {
2396 goto error;
2397 }
2398 } else {
2399 /* if this sig is the first one, sig_list should be null */
2400 sig->next = de_ctx->sig_list;
2401 }
2402
2403 de_ctx->sig_list = sig;
2404
2405 /**
2406 * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one
2407 * so if the signature is bidirectional, the returned sig will point through "next" ptr
2408 * to the cloned signatures with the switched addresses
2409 */
2410 return (dup_sig == 0 || dup_sig == 2) ? sig : NULL;
2411
2412 error:
2413 /* free the 2nd sig bidir may have set up */
2414 if (sig != NULL && sig->next != NULL) {
2415 SigFree(de_ctx, sig->next);
2416 sig->next = NULL;
2417 }
2418 if (sig != NULL) {
2419 SigFree(de_ctx, sig);
2420 }
2421 return NULL;
2422 }
2423
2424 static DetectParseRegex *g_detect_parse_regex_list = NULL;
DetectParsePcreExecLen(DetectParseRegex * parse_regex,const char * str,int str_len,int start_offset,int options,int * ovector,int ovector_size)2425 int DetectParsePcreExecLen(DetectParseRegex *parse_regex, const char *str,
2426 int str_len,
2427 int start_offset, int options,
2428 int *ovector, int ovector_size)
2429 {
2430 return pcre_exec(parse_regex->regex, parse_regex->study, str, str_len,
2431 start_offset, options, ovector, ovector_size);
2432 }
2433
DetectParsePcreExec(DetectParseRegex * parse_regex,const char * str,int start_offset,int options,int * ovector,int ovector_size)2434 int DetectParsePcreExec(DetectParseRegex *parse_regex, const char *str,
2435 int start_offset, int options,
2436 int *ovector, int ovector_size)
2437 {
2438 return pcre_exec(parse_regex->regex, parse_regex->study, str, strlen(str),
2439 start_offset, options, ovector, ovector_size);
2440 }
2441
DetectParseFreeRegex(DetectParseRegex * r)2442 void DetectParseFreeRegex(DetectParseRegex *r)
2443 {
2444 if (r->regex) {
2445 pcre_free(r->regex);
2446 }
2447 if (r->study) {
2448 pcre_free_study(r->study);
2449 }
2450 }
2451
DetectParseFreeRegexes(void)2452 void DetectParseFreeRegexes(void)
2453 {
2454 DetectParseRegex *r = g_detect_parse_regex_list;
2455 while (r) {
2456 DetectParseRegex *next = r->next;
2457
2458 DetectParseFreeRegex(r);
2459
2460 SCFree(r);
2461 r = next;
2462 }
2463 g_detect_parse_regex_list = NULL;
2464 }
2465
2466 /** \brief add regex and/or study to at exit free list
2467 */
DetectParseRegexAddToFreeList(DetectParseRegex * detect_parse)2468 void DetectParseRegexAddToFreeList(DetectParseRegex *detect_parse)
2469 {
2470 DetectParseRegex *r = SCCalloc(1, sizeof(*r));
2471 if (r == NULL) {
2472 FatalError(SC_ERR_MEM_ALLOC, "failed to alloc memory for pcre free list");
2473 }
2474 r->regex = detect_parse->regex;
2475 r->study = detect_parse->study;
2476 r->next = g_detect_parse_regex_list;
2477 g_detect_parse_regex_list = r;
2478 }
2479
DetectSetupParseRegexesOpts(const char * parse_str,DetectParseRegex * detect_parse,int opts)2480 bool DetectSetupParseRegexesOpts(const char *parse_str, DetectParseRegex *detect_parse, int opts)
2481 {
2482 const char *eb = NULL;
2483 int eo;
2484
2485 detect_parse->regex = pcre_compile(parse_str, opts, &eb, &eo, NULL);
2486 if (detect_parse->regex == NULL) {
2487 SCLogError(SC_ERR_PCRE_COMPILE, "pcre compile of \"%s\" failed at "
2488 "offset %" PRId32 ": %s", parse_str, eo, eb);
2489 return false;
2490 }
2491
2492 detect_parse->study = pcre_study(detect_parse->regex, 0 , &eb);
2493 if (eb != NULL) {
2494 SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb);
2495 return false;
2496 }
2497
2498
2499 DetectParseRegexAddToFreeList(detect_parse);
2500
2501 return true;
2502 }
2503
DetectSetupParseRegexes(const char * parse_str,DetectParseRegex * detect_parse)2504 void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
2505 {
2506 if (!DetectSetupParseRegexesOpts(parse_str, detect_parse, 0)) {
2507 FatalError(SC_ERR_PCRE_COMPILE, "pcre compile and study failed");
2508 }
2509 }
2510
2511
2512 /*
2513 * TESTS
2514 */
2515
2516 #ifdef UNITTESTS
SigParseTest01(void)2517 static int SigParseTest01 (void)
2518 {
2519 int result = 1;
2520 Signature *sig = NULL;
2521
2522 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2523 if (de_ctx == NULL)
2524 goto end;
2525
2526 sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
2527 if (sig == NULL)
2528 result = 0;
2529
2530 end:
2531 if (sig != NULL) SigFree(de_ctx, sig);
2532 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
2533 return result;
2534 }
2535
SigParseTest02(void)2536 static int SigParseTest02 (void)
2537 {
2538 int result = 0;
2539 Signature *sig = NULL;
2540 DetectPort *port = NULL;
2541
2542 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2543
2544 if (de_ctx == NULL)
2545 goto end;
2546
2547 FILE *fd = SCClassConfGenerateValidDummyClassConfigFD01();
2548 SCClassConfLoadClassficationConfigFile(de_ctx, fd);
2549
2550 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;)");
2551 if (sig == NULL) {
2552 goto end;
2553 }
2554
2555 int r = DetectPortParse(de_ctx, &port, "0:20");
2556 if (r < 0)
2557 goto end;
2558
2559 if (DetectPortCmp(sig->sp, port) == PORT_EQ) {
2560 result = 1;
2561 } else {
2562 DetectPortPrint(port); printf(" != "); DetectPortPrint(sig->sp); printf(": ");
2563 }
2564
2565 end:
2566 if (port != NULL)
2567 DetectPortCleanupList(de_ctx, port);
2568 if (sig != NULL)
2569 SigFree(de_ctx, sig);
2570 if (de_ctx != NULL)
2571 DetectEngineCtxFree(de_ctx);
2572 return result;
2573 }
2574
2575 /**
2576 * \test SigParseTest03 test for invalid direction operator in rule
2577 */
SigParseTest03(void)2578 static int SigParseTest03 (void)
2579 {
2580 int result = 1;
2581 Signature *sig = NULL;
2582
2583 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2584 if (de_ctx == NULL)
2585 goto end;
2586
2587 sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any <- !1.2.3.4 any (msg:\"SigParseTest03\"; sid:1;)");
2588 if (sig != NULL) {
2589 result = 0;
2590 printf("expected NULL got sig ptr %p: ",sig);
2591 }
2592
2593 end:
2594 if (sig != NULL) SigFree(de_ctx, sig);
2595 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
2596 return result;
2597 }
2598
SigParseTest04(void)2599 static int SigParseTest04 (void)
2600 {
2601 int result = 1;
2602 Signature *sig = NULL;
2603
2604 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2605 if (de_ctx == NULL)
2606 goto end;
2607
2608 sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024: -> !1.2.3.4 1024: (msg:\"SigParseTest04\"; sid:1;)");
2609 if (sig == NULL)
2610 result = 0;
2611
2612 end:
2613 if (sig != NULL) SigFree(de_ctx, sig);
2614 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
2615 return result;
2616 }
2617
2618 /** \test Port validation */
SigParseTest05(void)2619 static int SigParseTest05 (void)
2620 {
2621 int result = 0;
2622 Signature *sig = NULL;
2623
2624 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2625 if (de_ctx == NULL)
2626 goto end;
2627
2628 sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024:65536 -> !1.2.3.4 any (msg:\"SigParseTest05\"; sid:1;)");
2629 if (sig == NULL) {
2630 result = 1;
2631 } else {
2632 printf("signature didn't fail to parse as we expected: ");
2633 }
2634
2635 end:
2636 if (sig != NULL) SigFree(de_ctx, sig);
2637 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
2638 return result;
2639 }
2640
2641 /** \test Parsing bug debugging at 2010-03-18 */
SigParseTest06(void)2642 static int SigParseTest06 (void)
2643 {
2644 int result = 0;
2645 Signature *sig = NULL;
2646
2647 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2648 if (de_ctx == NULL)
2649 goto end;
2650
2651 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;)");
2652 if (sig != NULL) {
2653 result = 1;
2654 } else {
2655 printf("signature failed to parse: ");
2656 }
2657
2658 end:
2659 if (sig != NULL)
2660 SigFree(de_ctx, sig);
2661 if (de_ctx != NULL)
2662 DetectEngineCtxFree(de_ctx);
2663 return result;
2664 }
2665
2666 /**
2667 * \test Parsing duplicate sigs.
2668 */
SigParseTest07(void)2669 static int SigParseTest07(void)
2670 {
2671 int result = 0;
2672
2673 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2674 if (de_ctx == NULL)
2675 goto end;
2676
2677 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
2678 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
2679
2680 result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL);
2681
2682 end:
2683 if (de_ctx != NULL)
2684 DetectEngineCtxFree(de_ctx);
2685 return result;
2686 }
2687
2688 /**
2689 * \test Parsing duplicate sigs.
2690 */
SigParseTest08(void)2691 static int SigParseTest08(void)
2692 {
2693 int result = 0;
2694
2695 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2696 if (de_ctx == NULL)
2697 goto end;
2698
2699 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
2700 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)");
2701
2702 result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL &&
2703 de_ctx->sig_list->rev == 2);
2704
2705 end:
2706 if (de_ctx != NULL)
2707 DetectEngineCtxFree(de_ctx);
2708 return result;
2709 }
2710
2711 /**
2712 * \test Parsing duplicate sigs.
2713 */
SigParseTest09(void)2714 static int SigParseTest09(void)
2715 {
2716 int result = 1;
2717
2718 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2719 if (de_ctx == NULL)
2720 goto end;
2721
2722 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
2723 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)");
2724 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:6;)");
2725 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:4;)");
2726 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)");
2727 result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
2728 de_ctx->sig_list->rev == 2);
2729 if (result == 0)
2730 goto end;
2731 result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
2732 de_ctx->sig_list->next->rev == 6);
2733 if (result == 0)
2734 goto end;
2735
2736 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
2737 result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
2738 de_ctx->sig_list->rev == 2);
2739 if (result == 0)
2740 goto end;
2741 result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
2742 de_ctx->sig_list->next->rev == 6);
2743 if (result == 0)
2744 goto end;
2745
2746 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:4;)");
2747 result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
2748 de_ctx->sig_list->rev == 4);
2749 if (result == 0)
2750 goto end;
2751 result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
2752 de_ctx->sig_list->next->rev == 6);
2753 if (result == 0)
2754 goto end;
2755
2756 end:
2757 if (de_ctx != NULL)
2758 DetectEngineCtxFree(de_ctx);
2759 return result;
2760 }
2761
2762 /**
2763 * \test Parsing duplicate sigs.
2764 */
SigParseTest10(void)2765 static int SigParseTest10(void)
2766 {
2767 int result = 1;
2768
2769 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2770 if (de_ctx == NULL)
2771 goto end;
2772
2773 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
2774 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
2775 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:1;)");
2776 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:4; rev:1;)");
2777 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:5; rev:1;)");
2778 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:2;)");
2779 DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)");
2780
2781 result &= ((de_ctx->sig_list->id == 2) &&
2782 (de_ctx->sig_list->next->id == 3) &&
2783 (de_ctx->sig_list->next->next->id == 5) &&
2784 (de_ctx->sig_list->next->next->next->id == 4) &&
2785 (de_ctx->sig_list->next->next->next->next->id == 1));
2786
2787 end:
2788 if (de_ctx != NULL)
2789 DetectEngineCtxFree(de_ctx);
2790 return result;
2791 }
2792
2793 /**
2794 * \test Parsing sig with trailing space(s) as reported by
2795 * Morgan Cox on oisf-users.
2796 */
SigParseTest11(void)2797 static int SigParseTest11(void)
2798 {
2799 int result = 0;
2800
2801 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2802 if (de_ctx == NULL)
2803 goto end;
2804
2805 Signature *s = NULL;
2806
2807 s = DetectEngineAppendSig(de_ctx, "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking the http link\";) ");
2808 if (s == NULL) {
2809 printf("sig 1 didn't parse: ");
2810 goto end;
2811 }
2812
2813 s = DetectEngineAppendSig(de_ctx, "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking the http link\"; sid:1;) ");
2814 if (s == NULL) {
2815 printf("sig 2 didn't parse: ");
2816 goto end;
2817 }
2818
2819 result = 1;
2820 end:
2821 if (de_ctx != NULL)
2822 DetectEngineCtxFree(de_ctx);
2823 return result;
2824 }
2825
2826 /**
2827 * \test file_data with rawbytes
2828 */
SigParseTest12(void)2829 static int SigParseTest12(void)
2830 {
2831 int result = 0;
2832
2833 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2834 if (de_ctx == NULL)
2835 goto end;
2836
2837 Signature *s = NULL;
2838
2839 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (file_data; content:\"abc\"; rawbytes; sid:1;)");
2840 if (s != NULL) {
2841 printf("sig 1 should have given an error: ");
2842 goto end;
2843 }
2844
2845 result = 1;
2846 end:
2847 if (de_ctx != NULL)
2848 DetectEngineCtxFree(de_ctx);
2849 return result;
2850 }
2851
2852 /**
2853 * \test packet/stream sig
2854 */
SigParseTest13(void)2855 static int SigParseTest13(void)
2856 {
2857 int result = 0;
2858
2859 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2860 if (de_ctx == NULL)
2861 goto end;
2862
2863 Signature *s = NULL;
2864
2865 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; sid:1;)");
2866 if (s == NULL) {
2867 printf("sig 1 invalidated: failure");
2868 goto end;
2869 }
2870
2871 if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
2872 printf("sig doesn't have stream flag set\n");
2873 goto end;
2874 }
2875
2876 if (s->flags & SIG_FLAG_REQUIRE_PACKET) {
2877 printf("sig has packet flag set\n");
2878 goto end;
2879 }
2880
2881 result = 1;
2882
2883 end:
2884 if (de_ctx != NULL)
2885 DetectEngineCtxFree(de_ctx);
2886 return result;
2887 }
2888
2889 /**
2890 * \test packet/stream sig
2891 */
SigParseTest14(void)2892 static int SigParseTest14(void)
2893 {
2894 int result = 0;
2895
2896 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2897 if (de_ctx == NULL)
2898 goto end;
2899
2900 Signature *s = NULL;
2901
2902 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; dsize:>0; sid:1;)");
2903 if (s == NULL) {
2904 printf("sig 1 invalidated: failure");
2905 goto end;
2906 }
2907
2908 if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
2909 printf("sig doesn't have packet flag set\n");
2910 goto end;
2911 }
2912
2913 if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
2914 printf("sig has stream flag set\n");
2915 goto end;
2916 }
2917
2918 result = 1;
2919
2920 end:
2921 if (de_ctx != NULL)
2922 DetectEngineCtxFree(de_ctx);
2923 return result;
2924 }
2925
2926 /**
2927 * \test packet/stream sig
2928 */
SigParseTest15(void)2929 static int SigParseTest15(void)
2930 {
2931 int result = 0;
2932
2933 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2934 if (de_ctx == NULL)
2935 goto end;
2936
2937 Signature *s = NULL;
2938
2939 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:5; sid:1;)");
2940 if (s == NULL) {
2941 printf("sig 1 invalidated: failure");
2942 goto end;
2943 }
2944
2945 if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
2946 printf("sig doesn't have packet flag set\n");
2947 goto end;
2948 }
2949
2950 if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
2951 printf("sig doesn't have stream flag set\n");
2952 goto end;
2953 }
2954
2955 result = 1;
2956
2957 end:
2958 if (de_ctx != NULL)
2959 DetectEngineCtxFree(de_ctx);
2960 return result;
2961 }
2962
2963 /**
2964 * \test packet/stream sig
2965 */
SigParseTest16(void)2966 static int SigParseTest16(void)
2967 {
2968 int result = 0;
2969
2970 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2971 if (de_ctx == NULL)
2972 goto end;
2973
2974 Signature *s = NULL;
2975
2976 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; depth:5; sid:1;)");
2977 if (s == NULL) {
2978 printf("sig 1 invalidated: failure");
2979 goto end;
2980 }
2981
2982 if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
2983 printf("sig doesn't have packet flag set\n");
2984 goto end;
2985 }
2986
2987 if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
2988 printf("sig doesn't have stream flag set\n");
2989 goto end;
2990 }
2991
2992 result = 1;
2993
2994 end:
2995 if (de_ctx != NULL)
2996 DetectEngineCtxFree(de_ctx);
2997 return result;
2998 }
2999
3000 /**
3001 * \test packet/stream sig
3002 */
SigParseTest17(void)3003 static int SigParseTest17(void)
3004 {
3005 int result = 0;
3006
3007 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3008 if (de_ctx == NULL)
3009 goto end;
3010
3011 Signature *s = NULL;
3012
3013 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)");
3014 if (s == NULL) {
3015 printf("sig 1 invalidated: failure");
3016 goto end;
3017 }
3018
3019 if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
3020 printf("sig doesn't have packet flag set\n");
3021 goto end;
3022 }
3023
3024 if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
3025 printf("sig doesn't have stream flag set\n");
3026 goto end;
3027 }
3028
3029 result = 1;
3030
3031 end:
3032 if (de_ctx != NULL)
3033 DetectEngineCtxFree(de_ctx);
3034 return result;
3035 }
3036
3037 /** \test sid value too large. Bug #779 */
SigParseTest18(void)3038 static int SigParseTest18 (void)
3039 {
3040 int result = 0;
3041
3042 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3043 if (de_ctx == NULL)
3044 goto end;
3045
3046 if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:99999999999999999999;)") != NULL)
3047 goto end;
3048
3049 result = 1;
3050 end:
3051 if (de_ctx != NULL)
3052 DetectEngineCtxFree(de_ctx);
3053 return result;
3054 }
3055
3056 /** \test gid value too large. Related to bug #779 */
SigParseTest19(void)3057 static int SigParseTest19 (void)
3058 {
3059 int result = 0;
3060
3061 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3062 if (de_ctx == NULL)
3063 goto end;
3064
3065 if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; gid:99999999999999999999;)") != NULL)
3066 goto end;
3067
3068 result = 1;
3069 end:
3070 if (de_ctx != NULL)
3071 DetectEngineCtxFree(de_ctx);
3072 return result;
3073 }
3074
3075 /** \test rev value too large. Related to bug #779 */
SigParseTest20(void)3076 static int SigParseTest20 (void)
3077 {
3078 int result = 0;
3079
3080 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3081 if (de_ctx == NULL)
3082 goto end;
3083
3084 if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; rev:99999999999999999999;)") != NULL)
3085 goto end;
3086
3087 result = 1;
3088 end:
3089 if (de_ctx != NULL)
3090 DetectEngineCtxFree(de_ctx);
3091 return result;
3092 }
3093
3094 /** \test address parsing */
SigParseTest21(void)3095 static int SigParseTest21 (void)
3096 {
3097 int result = 0;
3098
3099 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3100 if (de_ctx == NULL)
3101 goto end;
3102
3103 if (DetectEngineAppendSig(de_ctx, "alert tcp [1.2.3.4, 1.2.3.5] any -> !1.2.3.4 any (sid:1;)") == NULL)
3104 goto end;
3105
3106 result = 1;
3107 end:
3108 if (de_ctx != NULL)
3109 DetectEngineCtxFree(de_ctx);
3110 return result;
3111 }
3112
3113 /** \test address parsing */
SigParseTest22(void)3114 static int SigParseTest22 (void)
3115 {
3116 int result = 0;
3117
3118 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3119 if (de_ctx == NULL)
3120 goto end;
3121
3122 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)
3123 goto end;
3124
3125 result = 1;
3126 end:
3127 if (de_ctx != NULL)
3128 DetectEngineCtxFree(de_ctx);
3129 return result;
3130 }
3131
3132 /**
3133 * \test rule ending in carriage return
3134 */
SigParseTest23(void)3135 static int SigParseTest23(void)
3136 {
3137 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3138 FAIL_IF_NULL(de_ctx);
3139
3140 Signature *s = NULL;
3141
3142 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)\r");
3143 FAIL_IF_NULL(s);
3144
3145 DetectEngineCtxFree(de_ctx);
3146 PASS;
3147 }
3148
3149 /** \test Direction operator validation (invalid) */
SigParseBidirecTest06(void)3150 static int SigParseBidirecTest06 (void)
3151 {
3152 int result = 1;
3153 Signature *sig = NULL;
3154
3155 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3156 if (de_ctx == NULL)
3157 goto end;
3158
3159 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any - 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
3160 if (sig == NULL)
3161 result = 1;
3162
3163 end:
3164 if (sig != NULL) SigFree(de_ctx, sig);
3165 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3166 return result;
3167 }
3168
3169 /** \test Direction operator validation (invalid) */
SigParseBidirecTest07(void)3170 static int SigParseBidirecTest07 (void)
3171 {
3172 int result = 1;
3173 Signature *sig = NULL;
3174
3175 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3176 if (de_ctx == NULL)
3177 goto end;
3178
3179 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
3180 if (sig == NULL)
3181 result = 1;
3182
3183 end:
3184 if (sig != NULL) SigFree(de_ctx, sig);
3185 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3186 return result;
3187 }
3188
3189 /** \test Direction operator validation (invalid) */
SigParseBidirecTest08(void)3190 static int SigParseBidirecTest08 (void)
3191 {
3192 int result = 1;
3193 Signature *sig = NULL;
3194
3195 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3196 if (de_ctx == NULL)
3197 goto end;
3198
3199 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any < 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
3200 if (sig == NULL)
3201 result = 1;
3202
3203 end:
3204 if (sig != NULL) SigFree(de_ctx, sig);
3205 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3206 return result;
3207 }
3208
3209 /** \test Direction operator validation (invalid) */
SigParseBidirecTest09(void)3210 static int SigParseBidirecTest09 (void)
3211 {
3212 int result = 1;
3213 Signature *sig = NULL;
3214
3215 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3216 if (de_ctx == NULL)
3217 goto end;
3218
3219 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any > 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
3220 if (sig == NULL)
3221 result = 1;
3222
3223 end:
3224 if (sig != NULL) SigFree(de_ctx, sig);
3225 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3226 return result;
3227 }
3228
3229 /** \test Direction operator validation (invalid) */
SigParseBidirecTest10(void)3230 static int SigParseBidirecTest10 (void)
3231 {
3232 int result = 1;
3233 Signature *sig = NULL;
3234
3235 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3236 if (de_ctx == NULL)
3237 goto end;
3238
3239 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
3240 if (sig == NULL)
3241 result = 1;
3242
3243 end:
3244 if (sig != NULL) SigFree(de_ctx, sig);
3245 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3246 return result;
3247 }
3248
3249 /** \test Direction operator validation (invalid) */
SigParseBidirecTest11(void)3250 static int SigParseBidirecTest11 (void)
3251 {
3252 int result = 1;
3253 Signature *sig = NULL;
3254
3255 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3256 if (de_ctx == NULL)
3257 goto end;
3258
3259 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
3260 if (sig == NULL)
3261 result = 1;
3262
3263 end:
3264 if (sig != NULL) SigFree(de_ctx, sig);
3265 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3266 return result;
3267 }
3268
3269 /** \test Direction operator validation (invalid) */
SigParseBidirecTest12(void)3270 static int SigParseBidirecTest12 (void)
3271 {
3272 int result = 1;
3273 Signature *sig = NULL;
3274
3275 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3276 if (de_ctx == NULL)
3277 goto end;
3278
3279 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
3280 if (sig == NULL)
3281 result = 1;
3282
3283 end:
3284 if (sig != NULL) SigFree(de_ctx, sig);
3285 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3286 return result;
3287 }
3288
3289 /** \test Direction operator validation (valid) */
SigParseBidirecTest13(void)3290 static int SigParseBidirecTest13 (void)
3291 {
3292 int result = 1;
3293 Signature *sig = NULL;
3294
3295 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3296 if (de_ctx == NULL)
3297 goto end;
3298
3299 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
3300 if (sig != NULL)
3301 result = 1;
3302
3303 end:
3304 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3305 return result;
3306 }
3307
3308 /** \test Direction operator validation (valid) */
SigParseBidirecTest14(void)3309 static int SigParseBidirecTest14 (void)
3310 {
3311 int result = 1;
3312 Signature *sig = NULL;
3313
3314 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3315 if (de_ctx == NULL)
3316 goto end;
3317
3318 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
3319 if (sig != NULL)
3320 result = 1;
3321
3322 end:
3323 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3324 return result;
3325 }
3326
3327 /** \test Ensure that we don't set bidirectional in a
3328 * normal (one direction) Signature
3329 */
SigTestBidirec01(void)3330 static int SigTestBidirec01 (void)
3331 {
3332 Signature *sig = NULL;
3333 int result = 0;
3334
3335 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3336 if (de_ctx == NULL)
3337 goto end;
3338
3339 sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 -> !1.2.3.4 any (msg:\"SigTestBidirec01\"; sid:1;)");
3340 if (sig == NULL)
3341 goto end;
3342 if (sig->next != NULL)
3343 goto end;
3344 if (sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC)
3345 goto end;
3346 if (de_ctx->signum != 1)
3347 goto end;
3348
3349 result = 1;
3350
3351 end:
3352 if (de_ctx != NULL) {
3353 SigCleanSignatures(de_ctx);
3354 SigGroupCleanup(de_ctx);
3355 DetectEngineCtxFree(de_ctx);
3356 }
3357 return result;
3358 }
3359
3360 /** \test Ensure that we set a bidirectional Signature correctly */
SigTestBidirec02(void)3361 static int SigTestBidirec02 (void)
3362 {
3363 int result = 0;
3364 Signature *sig = NULL;
3365 Signature *copy = NULL;
3366
3367 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3368 if (de_ctx == NULL)
3369 goto end;
3370
3371 de_ctx->flags |= DE_QUIET;
3372
3373 sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 <> !1.2.3.4 any (msg:\"SigTestBidirec02\"; sid:1;)");
3374 if (sig == NULL)
3375 goto end;
3376 if (de_ctx->sig_list != sig)
3377 goto end;
3378 if (!(sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
3379 goto end;
3380 if (sig->next == NULL)
3381 goto end;
3382 if (de_ctx->signum != 2)
3383 goto end;
3384 copy = sig->next;
3385 if (copy->next != NULL)
3386 goto end;
3387 if (!(copy->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
3388 goto end;
3389
3390 result = 1;
3391
3392 end:
3393 if (de_ctx != NULL) {
3394 SigCleanSignatures(de_ctx);
3395 SigGroupCleanup(de_ctx);
3396 DetectEngineCtxFree(de_ctx);
3397 }
3398
3399 return result;
3400 }
3401
3402 /** \test Ensure that we set a bidirectional Signature correctly
3403 * and we install it with the rest of the signatures, checking
3404 * also that it match with the correct addr directions
3405 */
SigTestBidirec03(void)3406 static int SigTestBidirec03 (void)
3407 {
3408 int result = 0;
3409 Signature *sig = NULL;
3410 Packet *p = NULL;
3411
3412 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3413 if (de_ctx == NULL)
3414 goto end;
3415
3416 de_ctx->flags |= DE_QUIET;
3417
3418 const char *sigs[3];
3419 sigs[0] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)";
3420 sigs[1] = "alert tcp any any <> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)";
3421 sigs[2] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)";
3422 UTHAppendSigs(de_ctx, sigs, 3);
3423
3424 /* Checking that bidirectional rules are set correctly */
3425 sig = de_ctx->sig_list;
3426 if (sig == NULL)
3427 goto end;
3428 if (sig->next == NULL)
3429 goto end;
3430 if (sig->next->next == NULL)
3431 goto end;
3432 if (sig->next->next->next == NULL)
3433 goto end;
3434 if (sig->next->next->next->next != NULL)
3435 goto end;
3436 if (de_ctx->signum != 4)
3437 goto end;
3438
3439 uint8_t rawpkt1_ether[] = {
3440 0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
3441 0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
3442 0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
3443 0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
3444 0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
3445 0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
3446 0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
3447 0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
3448 0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
3449 0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
3450 0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
3451 0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
3452 0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
3453 0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
3454 0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
3455 0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
3456 0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
3457 0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
3458 0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
3459 0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
3460 0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
3461 0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
3462 0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
3463 0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
3464 0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
3465 0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
3466 0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
3467 0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
3468 0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
3469 0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
3470 0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
3471 0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
3472 0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
3473 0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
3474 0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
3475 0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
3476 0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
3477 0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
3478 0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
3479 0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
3480 0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
3481 0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
3482 0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
3483 0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
3484 0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
3485 0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
3486 0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
3487 0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
3488 0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
3489 0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
3490 0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
3491 0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
3492 0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
3493 0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
3494 0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */
3495
3496 FlowInitConfig(FLOW_QUIET);
3497 p = UTHBuildPacketFromEth(rawpkt1_ether, sizeof(rawpkt1_ether));
3498 if (p == NULL) {
3499 SCLogDebug("Error building packet");
3500 goto end;
3501 }
3502 UTHMatchPackets(de_ctx, &p, 1);
3503
3504 uint32_t sids[3] = {1, 2, 3};
3505 uint32_t results[3] = {1, 1, 1};
3506 result = UTHCheckPacketMatchResults(p, sids, results, 1);
3507
3508 end:
3509 if (p != NULL) {
3510 PACKET_RECYCLE(p);
3511 SCFree(p);
3512 }
3513 if (de_ctx != NULL) {
3514 SigCleanSignatures(de_ctx);
3515 SigGroupCleanup(de_ctx);
3516 DetectEngineCtxFree(de_ctx);
3517 }
3518 FlowShutdown();
3519
3520 return result;
3521 }
3522
3523 /** \test Ensure that we set a bidirectional Signature correctly
3524 * and we install it with the rest of the signatures, checking
3525 * also that it match with the correct addr directions
3526 */
SigTestBidirec04(void)3527 static int SigTestBidirec04 (void)
3528 {
3529 int result = 0;
3530 Signature *sig = NULL;
3531 Packet *p = NULL;
3532
3533 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3534 if (de_ctx == NULL)
3535 goto end;
3536
3537 de_ctx->flags |= DE_QUIET;
3538
3539 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)");
3540 if (sig == NULL)
3541 goto end;
3542 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> any any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)");
3543 if (sig == NULL)
3544 goto end;
3545 if ( !(sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
3546 goto end;
3547 if (sig->next == NULL)
3548 goto end;
3549 if (sig->next->next == NULL)
3550 goto end;
3551 if (sig->next->next->next != NULL)
3552 goto end;
3553 if (de_ctx->signum != 3)
3554 goto end;
3555
3556 sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)");
3557 if (sig == NULL)
3558 goto end;
3559 if (sig->next == NULL)
3560 goto end;
3561 if (sig->next->next == NULL)
3562 goto end;
3563 if (sig->next->next->next == NULL)
3564 goto end;
3565 if (sig->next->next->next->next != NULL)
3566 goto end;
3567 if (de_ctx->signum != 4)
3568 goto end;
3569
3570 uint8_t rawpkt1_ether[] = {
3571 0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
3572 0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
3573 0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
3574 0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
3575 0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
3576 0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
3577 0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
3578 0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
3579 0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
3580 0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
3581 0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
3582 0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
3583 0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
3584 0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
3585 0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
3586 0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
3587 0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
3588 0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
3589 0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
3590 0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
3591 0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
3592 0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
3593 0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
3594 0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
3595 0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
3596 0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
3597 0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
3598 0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
3599 0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
3600 0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
3601 0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
3602 0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
3603 0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
3604 0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
3605 0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
3606 0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
3607 0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
3608 0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
3609 0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
3610 0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
3611 0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
3612 0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
3613 0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
3614 0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
3615 0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
3616 0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
3617 0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
3618 0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
3619 0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
3620 0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
3621 0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
3622 0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
3623 0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
3624 0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
3625 0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */
3626
3627 p = SCMalloc(SIZE_OF_PACKET);
3628 if (unlikely(p == NULL))
3629 return 0;
3630 DecodeThreadVars dtv;
3631 ThreadVars th_v;
3632 DetectEngineThreadCtx *det_ctx;
3633
3634 memset(&th_v, 0, sizeof(th_v));
3635 memset(p, 0, SIZE_OF_PACKET);
3636
3637 FlowInitConfig(FLOW_QUIET);
3638 DecodeEthernet(&th_v, &dtv, p, rawpkt1_ether, sizeof(rawpkt1_ether));
3639 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
3640
3641 /* At this point we have a list of 4 signatures. The last one
3642 is a copy of the second one. If we receive a packet
3643 with source 192.168.1.1 80, all the sids should match */
3644
3645 SigGroupBuild(de_ctx);
3646 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3647
3648 /* only sid 2 should match with a packet going to 192.168.1.1 port 80 */
3649 if (PacketAlertCheck(p, 1) <= 0 && PacketAlertCheck(p, 3) <= 0 &&
3650 PacketAlertCheck(p, 2) == 1) {
3651 result = 1;
3652 }
3653
3654 if (p != NULL) {
3655 PACKET_RECYCLE(p);
3656 }
3657 FlowShutdown();
3658 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
3659
3660 end:
3661 if (de_ctx != NULL) {
3662 SigCleanSignatures(de_ctx);
3663 SigGroupCleanup(de_ctx);
3664 DetectEngineCtxFree(de_ctx);
3665 }
3666
3667 if (p != NULL)
3668 SCFree(p);
3669 return result;
3670 }
3671
3672 /**
3673 * \test check that we don't allow invalid negation options
3674 */
SigParseTestNegation01(void)3675 static int SigParseTestNegation01 (void)
3676 {
3677 int result = 0;
3678 DetectEngineCtx *de_ctx;
3679 Signature *s=NULL;
3680
3681 de_ctx = DetectEngineCtxInit();
3682 if (de_ctx == NULL)
3683 goto end;
3684 de_ctx->flags |= DE_QUIET;
3685
3686 s = SigInit(de_ctx,"alert tcp !any any -> any any (msg:\"SigTest41-01 src address is !any \"; classtype:misc-activity; sid:410001; rev:1;)");
3687 if (s != NULL) {
3688 SigFree(de_ctx, s);
3689 goto end;
3690 }
3691
3692 result = 1;
3693 end:
3694 if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3695 return result;
3696 }
3697
3698 /**
3699 * \test check that we don't allow invalid negation options
3700 */
SigParseTestNegation02(void)3701 static int SigParseTestNegation02 (void)
3702 {
3703 int result = 0;
3704 DetectEngineCtx *de_ctx;
3705 Signature *s=NULL;
3706
3707 de_ctx = DetectEngineCtxInit();
3708 if (de_ctx == NULL)
3709 goto end;
3710 de_ctx->flags |= DE_QUIET;
3711
3712 s = SigInit(de_ctx,"alert tcp any !any -> any any (msg:\"SigTest41-02 src ip is !any \"; classtype:misc-activity; sid:410002; rev:1;)");
3713 if (s != NULL) {
3714 SigFree(de_ctx, s);
3715 goto end;
3716 }
3717
3718 result = 1;
3719 end:
3720 if (de_ctx != NULL)
3721 DetectEngineCtxFree(de_ctx);
3722 return result;
3723 }
3724 /**
3725 * \test check that we don't allow invalid negation options
3726 */
SigParseTestNegation03(void)3727 static int SigParseTestNegation03 (void)
3728 {
3729 int result = 0;
3730 DetectEngineCtx *de_ctx;
3731 Signature *s=NULL;
3732
3733 de_ctx = DetectEngineCtxInit();
3734 if (de_ctx == NULL)
3735 goto end;
3736 de_ctx->flags |= DE_QUIET;
3737
3738 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;)");
3739 if (s != NULL) {
3740 SigFree(de_ctx, s);
3741 goto end;
3742 }
3743
3744 result = 1;
3745 end:
3746 if (de_ctx != NULL)
3747 DetectEngineCtxFree(de_ctx);
3748 return result;
3749 }
3750 /**
3751 * \test check that we don't allow invalid negation options
3752 */
SigParseTestNegation04(void)3753 static int SigParseTestNegation04 (void)
3754 {
3755 int result = 0;
3756 DetectEngineCtx *de_ctx;
3757 Signature *s=NULL;
3758
3759 de_ctx = DetectEngineCtxInit();
3760 if (de_ctx == NULL)
3761 goto end;
3762 de_ctx->flags |= DE_QUIET;
3763
3764 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;)");
3765 if (s != NULL) {
3766 SigFree(de_ctx, s);
3767 goto end;
3768 }
3769
3770 result = 1;
3771 end:
3772 if (de_ctx != NULL)
3773 DetectEngineCtxFree(de_ctx);
3774 return result;
3775 }
3776 /**
3777 * \test check that we don't allow invalid negation options
3778 */
SigParseTestNegation05(void)3779 static int SigParseTestNegation05 (void)
3780 {
3781 int result = 0;
3782 DetectEngineCtx *de_ctx;
3783 Signature *s=NULL;
3784
3785 de_ctx = DetectEngineCtxInit();
3786 if (de_ctx == NULL)
3787 goto end;
3788 de_ctx->flags |= DE_QUIET;
3789
3790 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;)");
3791 if (s != NULL) {
3792 SigFree(de_ctx, s);
3793 goto end;
3794 }
3795
3796 result = 1;
3797 end:
3798 if (de_ctx != NULL)
3799 DetectEngineCtxFree(de_ctx);
3800 return result;
3801 }
3802 /**
3803 * \test check that we don't allow invalid negation options
3804 */
SigParseTestNegation06(void)3805 static int SigParseTestNegation06 (void)
3806 {
3807 int result = 0;
3808 DetectEngineCtx *de_ctx;
3809 Signature *s=NULL;
3810
3811 de_ctx = DetectEngineCtxInit();
3812 if (de_ctx == NULL)
3813 goto end;
3814 de_ctx->flags |= DE_QUIET;
3815
3816 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;)");
3817 if (s != NULL) {
3818 SigFree(de_ctx, s);
3819 goto end;
3820 }
3821
3822 result = 1;
3823 end:
3824 if (de_ctx != NULL)
3825 DetectEngineCtxFree(de_ctx);
3826 return result;
3827 }
3828
3829 /**
3830 * \test check that we don't allow invalid negation options
3831 */
SigParseTestNegation07(void)3832 static int SigParseTestNegation07 (void)
3833 {
3834 int result = 0;
3835 DetectEngineCtx *de_ctx;
3836 Signature *s=NULL;
3837
3838 de_ctx = DetectEngineCtxInit();
3839 if (de_ctx == NULL)
3840 goto end;
3841 de_ctx->flags |= DE_QUIET;
3842
3843 s = SigInit(de_ctx,"alert tcp any any -> [192.168.0.2,!192.168.0.0/24] any (msg:\"SigTest41-06 dst ip [192.168.0.2,!192.168.0.0/24] \"; classtype:misc-activity; sid:410006; rev:1;)");
3844 if (s != NULL) {
3845 SigFree(de_ctx, s);
3846 goto end;
3847 }
3848
3849 result = 1;
3850 end:
3851 if (de_ctx != NULL)
3852 DetectEngineCtxFree(de_ctx);
3853 return result;
3854 }
3855
3856 /**
3857 * \test check valid negation bug 1079
3858 */
SigParseTestNegation08(void)3859 static int SigParseTestNegation08 (void)
3860 {
3861 int result = 0;
3862 DetectEngineCtx *de_ctx;
3863 Signature *s=NULL;
3864
3865 de_ctx = DetectEngineCtxInit();
3866 if (de_ctx == NULL)
3867 goto end;
3868 de_ctx->flags |= DE_QUIET;
3869
3870 s = SigInit(de_ctx,"alert tcp any any -> [192.168.0.0/16,!192.168.0.0/24] any (sid:410006; rev:1;)");
3871 if (s == NULL) {
3872 goto end;
3873 }
3874
3875 result = 1;
3876 end:
3877 if (de_ctx != NULL)
3878 DetectEngineCtxFree(de_ctx);
3879 return result;
3880 }
3881
3882 /**
3883 * \test mpm
3884 */
SigParseTestMpm01(void)3885 static int SigParseTestMpm01 (void)
3886 {
3887 int result = 0;
3888 Signature *sig = NULL;
3889
3890 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3891 if (de_ctx == NULL)
3892 goto end;
3893
3894 sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; sid:1;)");
3895 if (sig == NULL) {
3896 printf("sig failed to init: ");
3897 goto end;
3898 }
3899
3900 if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
3901 printf("sig doesn't have content list: ");
3902 goto end;
3903 }
3904
3905 result = 1;
3906 end:
3907 if (sig != NULL)
3908 SigFree(de_ctx, sig);
3909 DetectEngineCtxFree(de_ctx);
3910 return result;
3911 }
3912
3913 /**
3914 * \test mpm
3915 */
SigParseTestMpm02(void)3916 static int SigParseTestMpm02 (void)
3917 {
3918 int result = 0;
3919 Signature *sig = NULL;
3920
3921 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
3922 if (de_ctx == NULL)
3923 goto end;
3924
3925 sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; content:\"abcdef\"; sid:1;)");
3926 if (sig == NULL) {
3927 printf("sig failed to init: ");
3928 goto end;
3929 }
3930
3931 if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
3932 printf("sig doesn't have content list: ");
3933 goto end;
3934 }
3935
3936 result = 1;
3937 end:
3938 if (sig != NULL)
3939 SigFree(de_ctx, sig);
3940 DetectEngineCtxFree(de_ctx);
3941 return result;
3942 }
3943
3944 /**
3945 * \test test tls (app layer) rule
3946 */
SigParseTestAppLayerTLS01(void)3947 static int SigParseTestAppLayerTLS01(void)
3948 {
3949 int result = 0;
3950 DetectEngineCtx *de_ctx;
3951 Signature *s=NULL;
3952
3953 de_ctx = DetectEngineCtxInit();
3954 if (de_ctx == NULL)
3955 goto end;
3956 de_ctx->flags |= DE_QUIET;
3957
3958 s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS01 \"; sid:410006; rev:1;)");
3959 if (s == NULL) {
3960 printf("parsing sig failed: ");
3961 goto end;
3962 }
3963
3964 if (s->alproto == 0) {
3965 printf("alproto not set: ");
3966 goto end;
3967 }
3968
3969 result = 1;
3970 end:
3971 if (s != NULL)
3972 SigFree(de_ctx, s);
3973 if (de_ctx != NULL)
3974 DetectEngineCtxFree(de_ctx);
3975
3976 return result;
3977 }
3978
3979 /**
3980 * \test test tls (app layer) rule
3981 */
SigParseTestAppLayerTLS02(void)3982 static int SigParseTestAppLayerTLS02(void)
3983 {
3984 int result = 0;
3985 DetectEngineCtx *de_ctx;
3986 Signature *s=NULL;
3987
3988 de_ctx = DetectEngineCtxInit();
3989 if (de_ctx == NULL)
3990 goto end;
3991 de_ctx->flags |= DE_QUIET;
3992
3993 s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS02 \"; tls.version:1.0; sid:410006; rev:1;)");
3994 if (s == NULL) {
3995 printf("parsing sig failed: ");
3996 goto end;
3997 }
3998
3999 if (s->alproto == 0) {
4000 printf("alproto not set: ");
4001 goto end;
4002 }
4003
4004 result = 1;
4005 end:
4006 if (s != NULL)
4007 SigFree(de_ctx, s);
4008 if (de_ctx != NULL)
4009 DetectEngineCtxFree(de_ctx);
4010 return result;
4011 }
4012
4013 /**
4014 * \test test tls (app layer) rule
4015 */
SigParseTestAppLayerTLS03(void)4016 static int SigParseTestAppLayerTLS03(void)
4017 {
4018 int result = 0;
4019 DetectEngineCtx *de_ctx;
4020 Signature *s=NULL;
4021
4022 de_ctx = DetectEngineCtxInit();
4023 if (de_ctx == NULL)
4024 goto end;
4025 de_ctx->flags |= DE_QUIET;
4026
4027 s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS03 \"; tls.version:2.5; sid:410006; rev:1;)");
4028 if (s != NULL) {
4029 SigFree(de_ctx, s);
4030 goto end;
4031 }
4032
4033 result = 1;
4034 end:
4035 if (de_ctx != NULL)
4036 DetectEngineCtxFree(de_ctx);
4037 return result;
4038 }
4039
SigParseTestUnblanacedQuotes01(void)4040 static int SigParseTestUnblanacedQuotes01(void)
4041 {
4042 DetectEngineCtx *de_ctx;
4043 Signature *s;
4044
4045 de_ctx = DetectEngineCtxInit();
4046 FAIL_IF_NULL(de_ctx);
4047 de_ctx->flags |= DE_QUIET;
4048
4049 s = SigInit(de_ctx, "alert http any any -> any any (msg:\"SigParseTestUnblanacedQuotes01\"; pcre:\"/\\/[a-z]+\\.php\\?[a-z]+?=\\d{7}&[a-z]+?=\\d{7,8}$/U\" flowbits:set,et.exploitkitlanding; classtype:trojan-activity; sid:2017078; rev:5;)");
4050 FAIL_IF_NOT_NULL(s);
4051
4052 PASS;
4053 }
4054
SigParseTestContentGtDsize01(void)4055 static int SigParseTestContentGtDsize01(void)
4056 {
4057 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4058 FAIL_IF_NULL(de_ctx);
4059 de_ctx->flags |= DE_QUIET;
4060
4061 Signature *s = SigInit(de_ctx,
4062 "alert http any any -> any any ("
4063 "dsize:21; content:\"0123456789001234567890|00 00|\"; "
4064 "sid:1; rev:1;)");
4065 FAIL_IF_NOT_NULL(s);
4066
4067 PASS;
4068 }
4069
SigParseTestContentGtDsize02(void)4070 static int SigParseTestContentGtDsize02(void)
4071 {
4072 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4073 FAIL_IF_NULL(de_ctx);
4074 de_ctx->flags |= DE_QUIET;
4075
4076 Signature *s = SigInit(de_ctx,
4077 "alert http any any -> any any ("
4078 "dsize:21; content:\"0123456789|00 00|\"; offset:10; "
4079 "sid:1; rev:1;)");
4080 FAIL_IF_NOT_NULL(s);
4081
4082 PASS;
4083 }
4084
SigParseBidirWithSameSrcAndDest01(void)4085 static int SigParseBidirWithSameSrcAndDest01(void)
4086 {
4087 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4088 FAIL_IF_NULL(de_ctx);
4089 de_ctx->flags |= DE_QUIET;
4090
4091 Signature *s = SigInit(de_ctx,
4092 "alert tcp any any <> any any (sid:1; rev:1;)");
4093 FAIL_IF_NULL(s);
4094 FAIL_IF_NOT_NULL(s->next);
4095 FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
4096
4097 SigFree(de_ctx, s);
4098
4099 s = SigInit(de_ctx,
4100 "alert tcp any [80, 81] <> any [81, 80] (sid:1; rev:1;)");
4101 FAIL_IF_NULL(s);
4102 FAIL_IF_NOT_NULL(s->next);
4103 FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
4104
4105 SigFree(de_ctx, s);
4106
4107 s = SigInit(de_ctx,
4108 "alert tcp [1.2.3.4, 5.6.7.8] [80, 81] <> [5.6.7.8, 1.2.3.4] [81, 80] (sid:1; rev:1;)");
4109 FAIL_IF_NULL(s);
4110 FAIL_IF_NOT_NULL(s->next);
4111 FAIL_IF(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
4112
4113 SigFree(de_ctx, s);
4114
4115 PASS;
4116 }
4117
SigParseBidirWithSameSrcAndDest02(void)4118 static int SigParseBidirWithSameSrcAndDest02(void)
4119 {
4120 DetectEngineCtx *de_ctx = DetectEngineCtxInit();
4121 FAIL_IF_NULL(de_ctx);
4122 de_ctx->flags |= DE_QUIET;
4123
4124 // Source is a subset of destination
4125 Signature *s = SigInit(de_ctx,
4126 "alert tcp 1.2.3.4 any <> [1.2.3.4, 5.6.7.8, ::1] any (sid:1; rev:1;)");
4127 FAIL_IF_NULL(s);
4128 FAIL_IF_NULL(s->next);
4129 FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
4130
4131 SigFree(de_ctx, s);
4132
4133 // Source is a subset of destination
4134 s = SigInit(de_ctx,
4135 "alert tcp [1.2.3.4, ::1] [80, 81, 82] <> [1.2.3.4, ::1] [80, 81] (sid:1; rev:1;)");
4136 FAIL_IF_NULL(s);
4137 FAIL_IF_NULL(s->next);
4138 FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
4139
4140 SigFree(de_ctx, s);
4141
4142 // Source intersects with destination
4143 s = SigInit(de_ctx,
4144 "alert tcp [1.2.3.4, ::1, ABCD:AAAA::1] [80] <> [1.2.3.4, ::1] [80, 81] (sid:1; rev:1;)");
4145 FAIL_IF_NULL(s);
4146 FAIL_IF_NULL(s->next);
4147 FAIL_IF_NOT(s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC);
4148
4149 SigFree(de_ctx, s);
4150
4151 PASS;
4152 }
4153
4154 #endif /* UNITTESTS */
4155
4156 #ifdef UNITTESTS
4157 void DetectParseRegisterTests (void);
4158 #include "tests/detect-parse.c"
4159 #endif
4160
SigParseRegisterTests(void)4161 void SigParseRegisterTests(void)
4162 {
4163 #ifdef UNITTESTS
4164 DetectParseRegisterTests();
4165
4166 UtRegisterTest("SigParseTest01", SigParseTest01);
4167 UtRegisterTest("SigParseTest02", SigParseTest02);
4168 UtRegisterTest("SigParseTest03", SigParseTest03);
4169 UtRegisterTest("SigParseTest04", SigParseTest04);
4170 UtRegisterTest("SigParseTest05", SigParseTest05);
4171 UtRegisterTest("SigParseTest06", SigParseTest06);
4172 UtRegisterTest("SigParseTest07", SigParseTest07);
4173 UtRegisterTest("SigParseTest08", SigParseTest08);
4174 UtRegisterTest("SigParseTest09", SigParseTest09);
4175 UtRegisterTest("SigParseTest10", SigParseTest10);
4176 UtRegisterTest("SigParseTest11", SigParseTest11);
4177 UtRegisterTest("SigParseTest12", SigParseTest12);
4178 UtRegisterTest("SigParseTest13", SigParseTest13);
4179 UtRegisterTest("SigParseTest14", SigParseTest14);
4180 UtRegisterTest("SigParseTest15", SigParseTest15);
4181 UtRegisterTest("SigParseTest16", SigParseTest16);
4182 UtRegisterTest("SigParseTest17", SigParseTest17);
4183 UtRegisterTest("SigParseTest18", SigParseTest18);
4184 UtRegisterTest("SigParseTest19", SigParseTest19);
4185 UtRegisterTest("SigParseTest20", SigParseTest20);
4186 UtRegisterTest("SigParseTest21 -- address with space", SigParseTest21);
4187 UtRegisterTest("SigParseTest22 -- address with space", SigParseTest22);
4188 UtRegisterTest("SigParseTest23 -- carriage return", SigParseTest23);
4189
4190 UtRegisterTest("SigParseBidirecTest06", SigParseBidirecTest06);
4191 UtRegisterTest("SigParseBidirecTest07", SigParseBidirecTest07);
4192 UtRegisterTest("SigParseBidirecTest08", SigParseBidirecTest08);
4193 UtRegisterTest("SigParseBidirecTest09", SigParseBidirecTest09);
4194 UtRegisterTest("SigParseBidirecTest10", SigParseBidirecTest10);
4195 UtRegisterTest("SigParseBidirecTest11", SigParseBidirecTest11);
4196 UtRegisterTest("SigParseBidirecTest12", SigParseBidirecTest12);
4197 UtRegisterTest("SigParseBidirecTest13", SigParseBidirecTest13);
4198 UtRegisterTest("SigParseBidirecTest14", SigParseBidirecTest14);
4199 UtRegisterTest("SigTestBidirec01", SigTestBidirec01);
4200 UtRegisterTest("SigTestBidirec02", SigTestBidirec02);
4201 UtRegisterTest("SigTestBidirec03", SigTestBidirec03);
4202 UtRegisterTest("SigTestBidirec04", SigTestBidirec04);
4203 UtRegisterTest("SigParseTestNegation01", SigParseTestNegation01);
4204 UtRegisterTest("SigParseTestNegation02", SigParseTestNegation02);
4205 UtRegisterTest("SigParseTestNegation03", SigParseTestNegation03);
4206 UtRegisterTest("SigParseTestNegation04", SigParseTestNegation04);
4207 UtRegisterTest("SigParseTestNegation05", SigParseTestNegation05);
4208 UtRegisterTest("SigParseTestNegation06", SigParseTestNegation06);
4209 UtRegisterTest("SigParseTestNegation07", SigParseTestNegation07);
4210 UtRegisterTest("SigParseTestNegation08", SigParseTestNegation08);
4211 UtRegisterTest("SigParseTestMpm01", SigParseTestMpm01);
4212 UtRegisterTest("SigParseTestMpm02", SigParseTestMpm02);
4213 UtRegisterTest("SigParseTestAppLayerTLS01", SigParseTestAppLayerTLS01);
4214 UtRegisterTest("SigParseTestAppLayerTLS02", SigParseTestAppLayerTLS02);
4215 UtRegisterTest("SigParseTestAppLayerTLS03", SigParseTestAppLayerTLS03);
4216 UtRegisterTest("SigParseTestUnblanacedQuotes01",
4217 SigParseTestUnblanacedQuotes01);
4218
4219 UtRegisterTest("SigParseTestContentGtDsize01",
4220 SigParseTestContentGtDsize01);
4221 UtRegisterTest("SigParseTestContentGtDsize02",
4222 SigParseTestContentGtDsize02);
4223
4224 UtRegisterTest("SigParseBidirWithSameSrcAndDest01",
4225 SigParseBidirWithSameSrcAndDest01);
4226 UtRegisterTest("SigParseBidirWithSameSrcAndDest02",
4227 SigParseBidirWithSameSrcAndDest02);
4228 #endif /* UNITTESTS */
4229 }
4230