suricata
detect-engine-port.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2019 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 * Ports part of the detection engine.
24 *
25 * \todo more unit testing
26 *
27 */
28
29#include "suricata-common.h"
30#include "decode.h"
31#include "detect.h"
32#include "flow-var.h"
33
34#include "util-cidr.h"
35#include "util-unittest.h"
37#include "util-rule-vars.h"
38
39#include "detect-parse.h"
40#include "detect-engine.h"
41#include "detect-engine-mpm.h"
42
44#include "detect-engine-port.h"
45
46#include "conf.h"
47#include "util-debug.h"
48#include "util-error.h"
49
50#include "pkt-var.h"
51#include "host.h"
52#include "util-profiling.h"
53#include "util-var.h"
54#include "util-byte.h"
55
56static int DetectPortCutNot(DetectPort *, DetectPort **);
57static int DetectPortCut(DetectEngineCtx *, DetectPort *, DetectPort *,
58 DetectPort **);
59DetectPort *PortParse(const char *str);
60static bool DetectPortIsValidRange(char *, uint16_t *);
61
62/**
63 * \brief Alloc a DetectPort structure and update counters
64 *
65 * \retval dp newly created DetectPort on success; or NULL in case of error.
66 */
68{
69 DetectPort *dp = SCCalloc(1, sizeof(DetectPort));
70 if (unlikely(dp == NULL))
71 return NULL;
72 return dp;
73}
74
75/**
76 * \brief Free a DetectPort and its members
77 *
78 * \param dp Pointer to the DetectPort that has to be freed.
79 */
81{
82 if (dp == NULL)
83 return;
84
85 /* only free the head if we have the original */
86 if (dp->sh != NULL && !(dp->flags & PORT_SIGGROUPHEAD_COPY)) {
88 }
89 dp->sh = NULL;
90
91 SCFree(dp);
92}
93
94/**
95 * \brief Helper function used to print the list of ports
96 * present in this DetectPort list.
97 *
98 * \param head Pointer to the DetectPort list head
99 */
101{
102 DetectPort *cur;
103#ifdef DEBUG
104 uint16_t cnt = 0;
105#endif
106 SCLogDebug("= list start:");
107 if (head != NULL) {
108 for (cur = head; cur != NULL; cur = cur->next) {
109 DetectPortPrint(cur);
110#ifdef DEBUG
111 cnt++;
112#endif
113 }
114 SCLogDebug(" ");
115 }
116 SCLogDebug("= list end (cnt %" PRIu32 ")", cnt);
117}
118
119/**
120 * \brief Free a DetectPort list and each of its members
121 *
122 * \param head Pointer to the DetectPort list head
123 */
125{
126 if (head == NULL)
127 return;
128
129 DetectPort *cur, *next;
130
131 for (cur = head; cur != NULL; ) {
132 next = cur->next;
133 cur->next = NULL;
135 cur = next;
136 }
137}
138
139/**
140 * \brief function for inserting a port group object. This also makes sure
141 * SigGroupContainer lists are handled correctly.
142 *
143 * \param de_ctx Pointer to the current detection engine context
144 * \param head Pointer to the DetectPort list head
145 * \param dp DetectPort to search in the DetectPort list
146 *
147 * \retval 1 inserted
148 * \retval 0 not inserted, memory of new is freed
149 * \retval -1 error
150 *
151 * \todo rewrite to avoid recursive calls
152 * */
154 DetectPort *new)
155{
156 if (new == NULL)
157 return 0;
158
159 //BUG_ON(new->next != NULL);
160 //BUG_ON(new->prev != NULL);
161
162 /* see if it already exists or overlaps with existing ports */
163 if (*head != NULL) {
164 DetectPort *cur = NULL;
165 int r = 0;
166
167 for (cur = *head; cur != NULL; cur = cur->next) {
168 r = DetectPortCmp(new,cur);
169 BUG_ON(r == PORT_ER);
170
171 /* if so, handle that */
172 if (r == PORT_EQ) {
173 SCLogDebug("PORT_EQ %p %p", cur, new);
174 /* exact overlap/match */
175 if (cur != new) {
177 return 0;
178 }
179 return 1;
180 } else if (r == PORT_GT) {
181 SCLogDebug("PORT_GT (cur->next %p)", cur->next);
182 /* only add it now if we are bigger than the last
183 * group. Otherwise we'll handle it later. */
184 if (cur->next == NULL) {
185 SCLogDebug("adding GT");
186 /* put in the list */
187 new->prev = cur;
188 cur->next = new;
189 return 1;
190 }
191 } else if (r == PORT_LT) {
192 SCLogDebug("PORT_LT");
193
194 /* see if we need to insert the ag anywhere */
195 /* put in the list */
196 if (cur->prev != NULL)
197 cur->prev->next = new;
198 new->prev = cur->prev;
199 new->next = cur;
200 cur->prev = new;
201
202 /* update head if required */
203 if (*head == cur) {
204 *head = new;
205 }
206 return 1;
207
208 /* alright, those were the simple cases,
209 * lets handle the more complex ones now */
210
211 } else {
212 DetectPort *c = NULL;
213 r = DetectPortCut(de_ctx, cur, new, &c);
214 if (r == -1)
215 goto error;
216
217 r = DetectPortInsert(de_ctx, head, new);
218 if (r == -1) {
219 if (c != NULL) {
221 }
222 goto error;
223 }
224
225 if (c != NULL) {
226 SCLogDebug("inserting C (%p)", c);
227 if (SCLogDebugEnabled()) {
229 }
231 if (r == -1)
232 goto error;
233 }
234 return 1;
235
236 }
237 }
238
239 /* head is NULL, so get a group and set head to it */
240 } else {
241 SCLogDebug("setting new head %p", new);
242 *head = new;
243 }
244
245 return 1;
246error:
247 /* XXX */
248 return -1;
249}
250
251/**
252 * \brief Function that cuts port groups and merge them
253 *
254 * \param de_ctx Pointer to the current detection engine context
255 * \param a pointer to DetectPort "a"
256 * \param b pointer to DetectPort "b"
257 * \param c pointer to DetectPort "c"
258 *
259 * \retval 0 ok
260 * \retval -1 error
261 * */
262static int DetectPortCut(DetectEngineCtx *de_ctx, DetectPort *a,
263 DetectPort *b, DetectPort **c)
264{
265 uint16_t a_port1 = a->port;
266 uint16_t a_port2 = a->port2;
267 uint16_t b_port1 = b->port;
268 uint16_t b_port2 = b->port2;
269
270 /* default to NULL */
271 *c = NULL;
272
273 int r = DetectPortCmp(a,b);
274 BUG_ON(r != PORT_ES && r != PORT_EB && r != PORT_LE && r != PORT_GE);
275
276 /* get a place to temporary put sigs lists */
277 DetectPort *tmp = DetectPortInit();
278 if (tmp == NULL) {
279 goto error;
280 }
281
282 /**
283 * We have 3 parts: [aaa[abab]bbb]
284 * part a: a_port1 <-> b_port1 - 1
285 * part b: b_port1 <-> a_port2
286 * part c: a_port2 + 1 <-> b_port2
287 */
288 if (r == PORT_LE) {
289 SCLogDebug("cut r == PORT_LE");
290 a->port = a_port1;
291 a->port2 = b_port1 - 1;
292
293 b->port = b_port1;
294 b->port2 = a_port2;
295
296 DetectPort *tmp_c = DetectPortInit();
297 if (tmp_c == NULL) {
298 goto error;
299 }
300 *c = tmp_c;
301
302 tmp_c->port = a_port2 + 1;
303 tmp_c->port2 = b_port2;
304
305 /**
306 * We have 3 parts: [bbb[baba]aaa]
307 * part a: b_port1 <-> a_port1 - 1
308 * part b: a_port1 <-> b_port2
309 * part c: b_port2 + 1 <-> a_port2
310 */
311 } else if (r == PORT_GE) {
312 SCLogDebug("cut r == PORT_GE");
313 a->port = b_port1;
314 a->port2 = a_port1 - 1;
315
316 b->port = a_port1;
317 b->port2 = b_port2;
318
319 DetectPort *tmp_c = DetectPortInit();
320 if (tmp_c == NULL) {
321 goto error;
322 }
323 *c = tmp_c;
324
325 tmp_c->port = b_port2 + 1;
326 tmp_c->port2 = a_port2;
327
328 /**
329 * We have 2 or three parts:
330 *
331 * 2 part: [[abab]bbb] or [bbb[baba]]
332 * part a: a_port1 <-> a_port2
333 * part b: a_port2 + 1 <-> b_port2
334 *
335 * part a: b_port1 <-> a_port1 - 1
336 * part b: a_port1 <-> a_port2
337 *
338 * 3 part [bbb[aaa]bbb]
339 * becomes[aaa[bbb]ccc]
340 *
341 * part a: b_port1 <-> a_port1 - 1
342 * part b: a_port1 <-> a_port2
343 * part c: a_port2 + 1 <-> b_port2
344 */
345 } else if (r == PORT_ES) {
346 SCLogDebug("cut r == PORT_ES");
347 if (a_port1 == b_port1) {
348 SCLogDebug("1");
349 a->port = a_port1;
350 a->port2 = a_port2;
351
352 b->port = a_port2 + 1;
353 b->port2 = b_port2;
354 } else if (a_port2 == b_port2) {
355 SCLogDebug("2");
356 a->port = b_port1;
357 a->port2 = a_port1 - 1;
358
359 b->port = a_port1;
360 b->port2 = a_port2;
361 } else {
362 SCLogDebug("3");
363 a->port = b_port1;
364 a->port2 = a_port1 - 1;
365
366 b->port = a_port1;
367 b->port2 = a_port2;
368
369 DetectPort *tmp_c = DetectPortInit();
370 if (tmp_c == NULL) {
371 goto error;
372 }
373 *c = tmp_c;
374
375 tmp_c->port = a_port2 + 1;
376 tmp_c->port2 = b_port2;
377 }
378 /**
379 * We have 2 or three parts:
380 *
381 * 2 part: [[baba]aaa] or [aaa[abab]]
382 * part a: b_port1 <-> b_port2
383 * part b: b_port2 + 1 <-> a_port2
384 *
385 * part a: a_port1 <-> b_port1 - 1
386 * part b: b_port1 <-> b_port2
387 *
388 * 3 part [aaa[bbb]aaa]
389 * becomes[aaa[bbb]ccc]
390 *
391 * part a: a_port1 <-> b_port2 - 1
392 * part b: b_port1 <-> b_port2
393 * part c: b_port2 + 1 <-> a_port2
394 */
395 } else if (r == PORT_EB) {
396 SCLogDebug("cut r == PORT_EB");
397 if (a_port1 == b_port1) {
398 SCLogDebug("1");
399 a->port = b_port1;
400 a->port2 = b_port2;
401
402 b->port = b_port2 + 1;
403 b->port2 = a_port2;
404 } else if (a_port2 == b_port2) {
405 SCLogDebug("2");
406
407 a->port = a_port1;
408 a->port2 = b_port1 - 1;
409
410 b->port = b_port1;
411 b->port2 = b_port2;
412
413 } else {
414 SCLogDebug("3");
415 a->port = a_port1;
416 a->port2 = b_port1 - 1;
417
418 b->port = b_port1;
419 b->port2 = b_port2;
420
421 DetectPort *tmp_c = DetectPortInit();
422 if (tmp_c == NULL) {
423 goto error;
424 }
425 *c = tmp_c;
426
427 tmp_c->port = b_port2 + 1;
428 tmp_c->port2 = a_port2;
429 }
430 }
431
432 if (tmp != NULL) {
434 }
435 return 0;
436
437error:
438 if (tmp != NULL)
440 return -1;
441}
442
443/**
444 * \brief Function that cuts port groups implementing group negation
445 *
446 * \param a pointer to DetectPort "a"
447 * \param b pointer to DetectPort "b"
448 *
449 * \retval 0 ok
450 * \retval -1 error
451 * */
452static int DetectPortCutNot(DetectPort *a, DetectPort **b)
453{
454 uint16_t a_port1 = a->port;
455 uint16_t a_port2 = a->port2;
456
457 /* default to NULL */
458 *b = NULL;
459
460 if (a_port1 != 0x0000 && a_port2 != 0xFFFF) {
461 a->port = 0x0000;
462 a->port2 = a_port1 - 1;
463
464 DetectPort *tmp_b;
465 tmp_b = DetectPortInit();
466 if (tmp_b == NULL) {
467 return -1;
468 }
469
470 tmp_b->port = a_port2 + 1;
471 tmp_b->port2 = 0xFFFF;
472 *b = tmp_b;
473
474 } else if (a_port1 == 0x0000 && a_port2 != 0xFFFF) {
475 a->port = a_port2 + 1;
476 a->port2 = 0xFFFF;
477
478 } else if (a_port1 != 0x0000 && a_port2 == 0xFFFF) {
479 a->port = 0x0000;
480 a->port2 = a_port1 - 1;
481 } else {
482 return -1;
483 }
484
485 return 0;
486}
487
488/**
489 * \brief Function that compare port groups
490 *
491 * \param a pointer to DetectPort "a"
492 * \param b pointer to DetectPort "b"
493 *
494 * \retval PORT_XX (Port enum value, XX is EQ, ES, EB, LE, etc)
495 * \retval PORT_ER on error
496 * */
498{
499 /* check any */
500 if ((a->flags & PORT_FLAG_ANY) && (b->flags & PORT_FLAG_ANY))
501 return PORT_EQ;
502 if ((a->flags & PORT_FLAG_ANY) && !(b->flags & PORT_FLAG_ANY))
503 return PORT_LT;
504 if (!(a->flags & PORT_FLAG_ANY) && (b->flags & PORT_FLAG_ANY))
505 return PORT_GT;
506
507 uint16_t a_port1 = a->port;
508 uint16_t a_port2 = a->port2;
509 uint16_t b_port1 = b->port;
510 uint16_t b_port2 = b->port2;
511
512 /* PORT_EQ */
513 if (a_port1 == b_port1 && a_port2 == b_port2) {
514 //SCLogDebug("PORT_EQ");
515 return PORT_EQ;
516 /* PORT_ES */
517 } else if (a_port1 >= b_port1 && a_port1 <= b_port2 && a_port2 <= b_port2) {
518 //SCLogDebug("PORT_ES");
519 return PORT_ES;
520 /* PORT_EB */
521 } else if (a_port1 <= b_port1 && a_port2 >= b_port2) {
522 //SCLogDebug("PORT_EB");
523 return PORT_EB;
524 } else if (a_port1 < b_port1 && a_port2 < b_port2 && a_port2 >= b_port1) {
525 //SCLogDebug("PORT_LE");
526 return PORT_LE;
527 } else if (a_port1 < b_port1 && a_port2 < b_port2) {
528 //SCLogDebug("PORT_LT");
529 return PORT_LT;
530 } else if (a_port1 > b_port1 && a_port1 <= b_port2 && a_port2 > b_port2) {
531 //SCLogDebug("PORT_GE");
532 return PORT_GE;
533 } else if (a_port1 > b_port2) {
534 //SCLogDebug("PORT_GT");
535 return PORT_GT;
536 }
537
538 return PORT_ER;
539}
540
541/**
542 * \brief Function that return a copy of DetectPort src sigs
543 *
544 * \param de_ctx Pointer to the current Detection Engine Context
545 * \param src Pointer to a DetectPort group to copy
546 *
547 * \retval Pointer to a DetectPort instance (copy of src)
548 * \retval NULL on error
549 * */
551{
552 if (src == NULL)
553 return NULL;
554
556 if (dst == NULL) {
557 return NULL;
558 }
559
560 dst->port = src->port;
561 dst->port2 = src->port2;
562
564 return dst;
565}
566
567/**
568 * \brief Function Match to Match a port against a DetectPort group
569 *
570 * \param dp Pointer to DetectPort group where we try to match the port
571 * \param port To compare/match
572 *
573 * \retval 1 if port is in the range (it match)
574 * \retval 0 if port is not in the range
575 * */
576static int DetectPortMatch(DetectPort *dp, uint16_t port)
577{
578 if (port >= dp->port &&
579 port <= dp->port2) {
580 return 1;
581 }
582
583 return 0;
584}
585
586/**
587 * \brief Helper function that print the DetectPort info
588 * \retval none
589 */
591{
592 if (dp == NULL)
593 return;
594
595 if (dp->flags & PORT_FLAG_ANY) {
596 SCLogDebug("=> port %p: ANY", dp);
597// printf("ANY");
598 } else {
599 SCLogDebug("=> port %p %" PRIu32 "-%" PRIu32 "", dp, dp->port, dp->port2);
600// printf("%" PRIu32 "-%" PRIu32 "", dp->port, dp->port2);
601 }
602}
603
604/**
605 * \brief Function that find the group matching port in a group head
606 *
607 * \param dp Pointer to DetectPort group where we try to find the group
608 * \param port port to search/lookup
609 *
610 * \retval Pointer to the DetectPort group of our port if it matched
611 * \retval NULL if port is not in the list
612 * */
614{
615 if (dp == NULL)
616 return NULL;
617
618 for (DetectPort *p = dp; p != NULL; p = p->next) {
619 if (DetectPortMatch(p, port) == 1) {
620 //SCLogDebug("match, port %" PRIu32 ", dp ", port);
621 //DetectPortPrint(p); SCLogDebug("");
622 return p;
623 }
624 }
625
626 return NULL;
627}
628
629/**
630 * \brief Checks if two port group lists are equal.
631 *
632 * \param list1 Pointer to the first port group list.
633 * \param list2 Pointer to the second port group list.
634 *
635 * \retval true On success.
636 * \retval false On failure.
637 */
639{
640 DetectPort *item = list1;
641 DetectPort *it = list2;
642
643 // First, compare items one by one.
644 while (item != NULL && it != NULL) {
645 if (DetectPortCmp(item, it) != PORT_EQ) {
646 return false;
647 }
648
649 item = item->next;
650 it = it->next;
651 }
652
653 // Are the lists of the same size?
654 if (!(item == NULL && it == NULL)) {
655 return false;
656 }
657
658 return true;
659}
660
661/******************* parsing routines ************************/
662
663/**
664 * \brief Wrapper function that call the internal/real function
665 * to insert the new DetectPort
666 * \param head Pointer to the head of the DetectPort group list
667 * \param new Pointer to the new DetectPort group list
668 *
669 * \retval 1 inserted
670 * \retval 0 not inserted, memory of new is freed
671 * \retval -1 error
672 */
673static int DetectPortParseInsert(DetectPort **head, DetectPort *new)
674{
675 return DetectPortInsert(NULL, head, new);
676}
677
678/**
679 * \brief Function to parse and insert the string in the DetectPort head list
680 *
681 * \param head Pointer to the head of the DetectPort group list
682 * \param s Pointer to the port string
683 *
684 * \retval 0 on success
685 * \retval -1 on error
686 */
687static int DetectPortParseInsertString(const DetectEngineCtx *de_ctx,
688 DetectPort **head, const char *s)
689{
690 DetectPort *port = NULL, *port_any = NULL;
691 int r = 0;
692 bool is_port_any = false;
693
694 SCLogDebug("head %p, *head %p, s %s", head, *head, s);
695
696 /** parse the port */
697 port = PortParse(s);
698 if (port == NULL) {
699 SCLogError(" failed to parse port \"%s\"", s);
700 return -1;
701 }
702
703 if (port->flags & PORT_FLAG_ANY) {
704 is_port_any = true;
705 }
706
707 /** handle the not case, we apply the negation then insert the part(s) */
708 if (port->flags & PORT_FLAG_NOT) {
709 DetectPort *port2 = NULL;
710
711 if (DetectPortCutNot(port, &port2) < 0) {
712 goto error;
713 }
714
715 /** normally, a 'not' will at most result in two ports */
716 if (port2 != NULL) {
717 if (DetectPortParseInsert(head, port2) < 0) {
718 if (port2 != NULL)
719 SCFree(port2);
720 goto error;
721 }
722 }
723 }
724
725 r = DetectPortParseInsert(head, port);
726 if (r < 0)
727 goto error;
728
729 /** if any, insert [0:65535] */
730 if (r == 1 && is_port_any) {
731 SCLogDebug("inserting 0:65535 as port is \"any\"");
732
733 port_any = PortParse("0:65535");
734 if (port_any == NULL)
735 goto error;
736
737 if (DetectPortParseInsert(head, port_any) < 0)
738 goto error;
739 }
740
741 return 0;
742
743error:
744 SCLogError("DetectPortParseInsertString error");
745 if (port != NULL)
747 if (port_any != NULL)
748 DetectPortCleanupList(de_ctx, port_any);
749 return -1;
750}
751
752/**
753 * \brief Parses a port string and updates the 2 port heads with the
754 * port groups.
755 *
756 * \todo We don't seem to be handling negated cases, like [port,![!port,port]],
757 * since we pass around negate without keeping a count of ! with depth.
758 * Can solve this by keeping a count of the negations with depth, so that
759 * an even no of negations would count as no negation and an odd no of
760 * negations would count as a negation.
761 *
762 * \param gh Pointer to the port group head that should hold port ranges
763 * that are not negated.
764 * \param ghn Pointer to the port group head that should hold port ranges
765 * that are negated.
766 * \param s Pointer to the character string holding the port to be
767 * parsed.
768 * \param negate Flag that indicates if the received port string is negated
769 * or not. 0 if it is not, 1 it it is.
770 *
771 * \retval 0 On successfully parsing.
772 * \retval -1 On failure.
773 */
774static int DetectPortParseDo(const DetectEngineCtx *de_ctx,
775 DetectPort **head, DetectPort **nhead,
776 const char *s, int negate,
777 ResolvedVariablesList *var_list, int recur)
778{
779 size_t u = 0;
780 size_t x = 0;
781 int o_set = 0, n_set = 0, d_set = 0;
782 int range = 0;
783 int depth = 0;
784 size_t size = strlen(s);
785 char port[1024] = "";
786 const char *rule_var_port = NULL;
787 int r = 0;
788
789 if (recur++ > 64) {
790 SCLogError("port block recursion "
791 "limit reached (max 64)");
792 goto error;
793 }
794
795 SCLogDebug("head %p, *head %p, negate %d", head, *head, negate);
796
797 for (u = 0, x = 0; u < size && x < sizeof(port); u++) {
798 port[x] = s[u];
799 x++;
800
801 if (s[u] == ':')
802 range = 1;
803
804 if (range == 1 && s[u] == '!') {
805 SCLogError("Can't have a negated value in a range.");
806 return -1;
807 } else if (!o_set && s[u] == '!') {
808 SCLogDebug("negation encountered");
809 n_set = 1;
810 x--;
811 } else if (s[u] == '[') {
812 if (!o_set) {
813 o_set = 1;
814 x = 0;
815 }
816 depth++;
817 } else if (s[u] == ']') {
818 if (depth == 1) {
819 port[x - 1] = '\0';
820 SCLogDebug("Parsed port from DetectPortParseDo - %s", port);
821 x = 0;
822
823 r = DetectPortParseDo(
824 de_ctx, head, nhead, port, negate ? negate : n_set, var_list, recur);
825 if (r == -1)
826 goto error;
827
828 n_set = 0;
829 }
830 depth--;
831 range = 0;
832 } else if (depth == 0 && s[u] == ',') {
833 if (o_set == 1) {
834 o_set = 0;
835 } else if (d_set == 1) {
836 char *temp_rule_var_port = NULL,
837 *alloc_rule_var_port = NULL;
838
839 port[x - 1] = '\0';
840
842 if (rule_var_port == NULL)
843 goto error;
844 if (strlen(rule_var_port) == 0) {
845 SCLogError("variable %s resolved "
846 "to nothing. This is likely a misconfiguration. "
847 "Note that a negated port needs to be quoted, "
848 "\"!$HTTP_PORTS\" instead of !$HTTP_PORTS. See issue #295.",
849 s);
850 goto error;
851 }
852 if (negate == 1 || n_set == 1) {
853 alloc_rule_var_port = SCMalloc(strlen(rule_var_port) + 3);
854 if (unlikely(alloc_rule_var_port == NULL))
855 goto error;
856 snprintf(alloc_rule_var_port, strlen(rule_var_port) + 3,
857 "[%s]", rule_var_port);
858 } else {
859 alloc_rule_var_port = SCStrdup(rule_var_port);
860 if (unlikely(alloc_rule_var_port == NULL))
861 goto error;
862 }
863 temp_rule_var_port = alloc_rule_var_port;
864 r = DetectPortParseDo(de_ctx, head, nhead, temp_rule_var_port,
865 (negate + n_set) % 2, var_list, recur);
866 if (r == -1) {
867 SCFree(alloc_rule_var_port);
868 goto error;
869 }
870 d_set = 0;
871 n_set = 0;
872 SCFree(alloc_rule_var_port);
873 } else {
874 port[x - 1] = '\0';
875 SCLogDebug("Parsed port from DetectPortParseDo - %s", port);
876
877 if (negate == 0 && n_set == 0) {
878 r = DetectPortParseInsertString(de_ctx, head, port);
879 } else {
880 r = DetectPortParseInsertString(de_ctx, nhead, port);
881 }
882 if (r == -1)
883 goto error;
884
885 n_set = 0;
886 }
887 x = 0;
888 range = 0;
889 } else if (depth == 0 && s[u] == '$') {
890 d_set = 1;
891 } else if (depth == 0 && u == size-1) {
892 range = 0;
893 if (x == 1024) {
894 port[x - 1] = '\0';
895 } else {
896 port[x] = '\0';
897 }
898 SCLogDebug("%s", port);
899
900 if (AddVariableToResolveList(var_list, port) == -1) {
901 SCLogError("Found a loop in a port "
902 "groups declaration. This is likely a misconfiguration.");
903 goto error;
904 }
905
906 x = 0;
907 if (d_set == 1) {
908 char *temp_rule_var_port = NULL,
909 *alloc_rule_var_port = NULL;
910
912 if (rule_var_port == NULL)
913 goto error;
914 if (strlen(rule_var_port) == 0) {
915 SCLogError("variable %s resolved "
916 "to nothing. This is likely a misconfiguration. "
917 "Note that a negated port needs to be quoted, "
918 "\"!$HTTP_PORTS\" instead of !$HTTP_PORTS. See issue #295.",
919 s);
920 goto error;
921 }
922 if ((negate + n_set) % 2) {
923 alloc_rule_var_port = SCMalloc(strlen(rule_var_port) + 3);
924 if (unlikely(alloc_rule_var_port == NULL))
925 goto error;
926 snprintf(alloc_rule_var_port, strlen(rule_var_port) + 3,
927 "[%s]", rule_var_port);
928 } else {
929 alloc_rule_var_port = SCStrdup(rule_var_port);
930 if (unlikely(alloc_rule_var_port == NULL))
931 goto error;
932 }
933 temp_rule_var_port = alloc_rule_var_port;
934 r = DetectPortParseDo(de_ctx, head, nhead, temp_rule_var_port,
935 (negate + n_set) % 2, var_list, recur);
936 SCFree(alloc_rule_var_port);
937 if (r == -1)
938 goto error;
939
940 d_set = 0;
941 } else {
942 if (!((negate + n_set) % 2)) {
943 r = DetectPortParseInsertString(de_ctx, head, port);
944 } else {
945 r = DetectPortParseInsertString(de_ctx, nhead, port);
946 }
947 if (r == -1)
948 goto error;
949 }
950 n_set = 0;
951 } else if (depth == 1 && s[u] == ',') {
952 range = 0;
953 }
954 }
955
956 if (depth > 0) {
957 SCLogError("not every port block was "
958 "properly closed in \"%s\", %d missing closing brackets (]). "
959 "Note: problem might be in a variable.",
960 s, depth);
961 goto error;
962 } else if (depth < 0) {
963 SCLogError("not every port block was "
964 "properly opened in \"%s\", %d missing opening brackets ([). "
965 "Note: problem might be in a variable.",
966 s, depth * -1);
967 goto error;
968 }
969
970 return 0;
971error:
972 return -1;
973}
974
975/**
976 * \brief Check if the port group list covers the complete port space.
977 * \retval 0 no
978 * \retval 1 yes
979 */
980static int DetectPortIsCompletePortSpace(DetectPort *p)
981{
982 uint16_t next_port = 0;
983
984 if (p == NULL)
985 return 0;
986
987 if (p->port != 0x0000)
988 return 0;
989
990 /* if we're ending with 0xFFFF while we know
991 we started with 0x0000 it's the complete space */
992 if (p->port2 == 0xFFFF)
993 return 1;
994
995 next_port = p->port2 + 1;
996 p = p->next;
997
998 for ( ; p != NULL; p = p->next) {
999 if (p->port != next_port)
1000 return 0;
1001
1002 if (p->port2 == 0xFFFF)
1003 return 1;
1004
1005 next_port = p->port2 + 1;
1006 }
1007
1008 return 0;
1009}
1010
1011/**
1012 * \brief Helper function for the parsing process
1013 *
1014 * \param head Pointer to the head of the DetectPort group list
1015 * \param nhead Pointer to the new head of the DetectPort group list
1016 *
1017 * \retval 0 on success
1018 * \retval -1 on error
1019 */
1020static int DetectPortParseMergeNotPorts(const DetectEngineCtx *de_ctx,
1021 DetectPort **head, DetectPort **nhead)
1022{
1023 DetectPort *port = NULL;
1024 DetectPort *pg, *pg2;
1025 int r = 0;
1026
1027 /** check if the full port space is negated */
1028 if (DetectPortIsCompletePortSpace(*nhead) == 1) {
1029 SCLogError("Complete port space is negated");
1030 goto error;
1031 }
1032
1033 /**
1034 * step 0: if the head list is empty, but the nhead list isn't
1035 * we have a pure not thingy. In that case we add a 0:65535
1036 * first.
1037 */
1038 if (*head == NULL && *nhead != NULL) {
1039 SCLogDebug("inserting 0:65535 into head");
1040 r = DetectPortParseInsertString(de_ctx, head,"0:65535");
1041 if (r < 0) {
1042 goto error;
1043 }
1044 }
1045
1046 /** step 1: insert our ghn members into the gh list */
1047 for (pg = *nhead; pg != NULL; pg = pg->next) {
1048 /** work with a copy of the port so we can easily clean up
1049 * the ghn group later.
1050 */
1051 port = DetectPortCopySingle(NULL, pg);
1052 if (port == NULL) {
1053 goto error;
1054 }
1055 r = DetectPortParseInsert(head, port);
1056 if (r < 0) {
1057 goto error;
1058 }
1059 port = NULL;
1060 }
1061
1062 /** step 2: pull the port blocks that match our 'not' blocks */
1063 for (pg = *nhead; pg != NULL; pg = pg->next) {
1064 SCLogDebug("pg %p", pg);
1065 DetectPortPrint(pg);
1066
1067 for (pg2 = *head; pg2 != NULL;) {
1068 SCLogDebug("pg2 %p", pg2);
1069 DetectPortPrint(pg2);
1070
1071 r = DetectPortCmp(pg, pg2);
1072 if (r == PORT_EQ || r == PORT_EB) { /* XXX more ??? */
1073 if (pg2->prev != NULL)
1074 pg2->prev->next = pg2->next;
1075 if (pg2->next != NULL)
1076 pg2->next->prev = pg2->prev;
1077 if (*head == pg2)
1078 *head = pg2->next;
1079 /** store the next ptr and remove the group */
1080 DetectPort *next_pg2 = pg2->next;
1081 DetectPortFree(de_ctx, pg2);
1082 pg2 = next_pg2;
1083 } else {
1084 pg2 = pg2->next;
1085 }
1086 }
1087 }
1088
1089 for (pg2 = *head; pg2 != NULL; pg2 = pg2->next) {
1090 SCLogDebug("pg2 %p", pg2);
1091 DetectPortPrint(pg2);
1092 }
1093
1094 if (*head == NULL) {
1095 SCLogError("no ports left after merging ports with negated ports");
1096 goto error;
1097 }
1098
1099 return 0;
1100error:
1101 if (port != NULL)
1102 DetectPortFree(de_ctx, port);
1103 return -1;
1104}
1105
1107{
1108 SCLogDebug("Testing port conf vars for any misconfigured values");
1109
1110 ResolvedVariablesList var_list = TAILQ_HEAD_INITIALIZER(var_list);
1111
1112 SCConfNode *port_vars_node = SCConfGetNode("vars.port-groups");
1113 if (port_vars_node == NULL) {
1114 return 0;
1115 }
1116
1117 SCConfNode *seq_node;
1118 TAILQ_FOREACH(seq_node, &port_vars_node->head, next) {
1119 SCLogDebug("Testing %s - %s\n", seq_node->name, seq_node->val);
1120
1121 DetectPort *gh = DetectPortInit();
1122 if (gh == NULL) {
1123 goto error;
1124 }
1125 DetectPort *ghn = NULL;
1126
1127 if (seq_node->val == NULL) {
1128 SCLogError("Port var \"%s\" probably has a sequence(something "
1129 "in brackets) value set without any quotes. Please "
1130 "quote it using \"..\".",
1131 seq_node->name);
1132 DetectPortCleanupList(NULL, gh);
1133 goto error;
1134 }
1135
1136 int r = DetectPortParseDo(NULL, &gh, &ghn, seq_node->val,
1137 /* start with negate no */0, &var_list, 0);
1138
1139 CleanVariableResolveList(&var_list);
1140
1141 if (r < 0) {
1142 DetectPortCleanupList(NULL, gh);
1143 SCLogError("failed to parse port var \"%s\" with value \"%s\". "
1144 "Please check its syntax",
1145 seq_node->name, seq_node->val);
1146 goto error;
1147 }
1148
1149 if (DetectPortIsCompletePortSpace(ghn)) {
1150 SCLogError("Port var - \"%s\" has the complete Port range negated "
1151 "with its value \"%s\". Port space range is NIL. "
1152 "Probably have a !any or a port range that supplies "
1153 "a NULL port range",
1154 seq_node->name, seq_node->val);
1155 DetectPortCleanupList(NULL, gh);
1156 DetectPortCleanupList(NULL, ghn);
1157 goto error;
1158 }
1159
1160 if (gh != NULL)
1161 DetectPortCleanupList(NULL, gh);
1162 if (ghn != NULL)
1163 DetectPortCleanupList(NULL, ghn);
1164 }
1165
1166 return 0;
1167 error:
1168 return -1;
1169}
1170
1171
1172/**
1173 * \brief Function for parsing port strings
1174 *
1175 * \param de_ctx Pointer to the detection engine context
1176 * \param head Pointer to the head of the DetectPort group list
1177 * \param str Pointer to the port string
1178 *
1179 * \retval 0 on success
1180 * \retval -1 on error
1181 */
1183 DetectPort **head, const char *str)
1184{
1185 SCLogDebug("Port string to be parsed - str %s", str);
1186
1187 /* negate port list */
1188 DetectPort *nhead = NULL;
1189
1190 int r = DetectPortParseDo(de_ctx, head, &nhead, str,
1191 /* start with negate no */ 0, NULL, 0);
1192 if (r < 0)
1193 goto error;
1194
1195 SCLogDebug("head %p %p, nhead %p", head, *head, nhead);
1196
1197 /* merge the 'not' port groups */
1198 if (DetectPortParseMergeNotPorts(de_ctx, head, &nhead) < 0)
1199 goto error;
1200
1201 /* free the temp negate head */
1203 return 0;
1204
1205error:
1207 return -1;
1208}
1209
1210/**
1211 * \brief Helper function for parsing port strings
1212 *
1213 * \param str Pointer to the port string
1214 *
1215 * \retval DetectPort pointer of the parse string on success
1216 * \retval NULL on error
1217 */
1219{
1220 char *port2 = NULL;
1221 char portstr[16];
1222
1223 /* strip leading spaces */
1224 while (isspace(*str))
1225 str++;
1226 if (strlen(str) >= 16)
1227 return NULL;
1228 strlcpy(portstr, str, sizeof(portstr));
1229
1230 DetectPort *dp = DetectPortInit();
1231 if (dp == NULL)
1232 goto error;
1233
1234 /* we dup so we can put a nul-termination in it later */
1235 char *port = portstr;
1236
1237 /* handle the negation case */
1238 if (port[0] == '!') {
1239 dp->flags |= PORT_FLAG_NOT;
1240 port++;
1241 }
1242
1243 if ((port2 = strchr(port, ':')) != NULL) {
1244 /* 80:81 range format */
1245 port2[0] = '\0';
1246 port2++;
1247
1248 if (strcmp(port, "") != 0) {
1249 if (!DetectPortIsValidRange(port, &dp->port))
1250 goto error;
1251 } else {
1252 dp->port = 0;
1253 }
1254
1255 if (strcmp(port2, "") != 0) {
1256 if (!DetectPortIsValidRange(port2, &dp->port2))
1257 goto error;
1258 } else {
1259 dp->port2 = 65535;
1260 }
1261
1262 /* a > b is illegal, a == b is ok */
1263 if (dp->port > dp->port2)
1264 goto error;
1265 } else {
1266 if (strcasecmp(port,"any") == 0) {
1267 dp->port = 0;
1268 dp->port2 = 65535;
1269 } else {
1270 if (!DetectPortIsValidRange(port, &dp->port))
1271 goto error;
1272 dp->port2 = dp->port;
1273 }
1274 }
1275
1276 return dp;
1277
1278error:
1279 if (dp != NULL)
1280 DetectPortCleanupList(NULL, dp);
1281 return NULL;
1282}
1283
1284/**
1285 * \brief Helper function to check if a parsed port is in the valid range
1286 * of available ports
1287 *
1288 * \param str Pointer to the port string
1289 *
1290 *
1291 * \retval true if port is in the valid range
1292 * \retval false if invalid
1293 */
1294static bool DetectPortIsValidRange(char *port, uint16_t *port_val)
1295{
1296 if (StringParseUint16(port_val, 10, 0, (const char *)port) < 0)
1297 return false;
1298
1299 return true;
1300}
1301
1302/********************** End parsing routines ********************/
1303
1304/* hash table */
1305
1306/**
1307 * \brief The hash function to be the used by the hash table -
1308 * DetectEngineCtx->dport_hash_table.
1309 *
1310 * \param ht Pointer to the hash table.
1311 * \param data Pointer to the DetectPort.
1312 * \param datalen Not used in our case.
1313 *
1314 * \retval hash The generated hash value.
1315 */
1316static uint32_t DetectPortHashFunc(HashListTable *ht, void *data, uint16_t datalen)
1317{
1318 DetectPort *p = (DetectPort *)data;
1319 SCLogDebug("hashing port %p", p);
1320
1321 uint32_t hash = ((uint32_t)p->port << 16) | p->port2;
1322
1323 hash %= ht->array_size;
1324 SCLogDebug("hash %"PRIu32, hash);
1325 return hash;
1326}
1327
1328/**
1329 * \brief The Compare function to be used by the DetectPort hash table -
1330 * DetectEngineCtx->dport_hash_table.
1331 *
1332 * \param data1 Pointer to the first DetectPort.
1333 * \param len1 Not used.
1334 * \param data2 Pointer to the second DetectPort.
1335 * \param len2 Not used.
1336 *
1337 * \retval 1 If the 2 DetectPort sent as args match.
1338 * \retval 0 If the 2 DetectPort sent as args do not match.
1339 */
1340static char DetectPortCompareFunc(void *data1, uint16_t len1,
1341 void *data2, uint16_t len2)
1342{
1343 DetectPort *dp1 = (DetectPort *)data1;
1344 DetectPort *dp2 = (DetectPort *)data2;
1345
1346 if (data1 == NULL || data2 == NULL)
1347 return 0;
1348
1349 if (dp1->port == dp2->port && dp1->port2 == dp2->port2)
1350 return 1;
1351
1352 return 0;
1353}
1354
1355static void DetectPortHashFreeFunc(void *ptr)
1356{
1357 DetectPort *p = ptr;
1358 DetectPortFree(NULL, p);
1359}
1360
1361/**
1362 * \brief Initializes the hash table in the detection engine context to hold the
1363 * DetectPort hash.
1364 *
1365 * \param de_ctx Pointer to the detection engine context.
1366 *
1367 * \retval 0 On success.
1368 * \retval -1 On failure.
1369 */
1371{
1372 de_ctx->dport_hash_table = HashListTableInit(4096, DetectPortHashFunc,
1373 DetectPortCompareFunc,
1374 DetectPortHashFreeFunc);
1375 if (de_ctx->dport_hash_table == NULL)
1376 return -1;
1377
1378 return 0;
1379}
1380
1381/**
1382 * \brief Adds a DetectPort to the detection engine context DetectPort
1383 * hash table.
1384 *
1385 * \param de_ctx Pointer to the detection engine context.
1386 * \param dp Pointer to the DetectPort.
1387 *
1388 * \retval ret 0 on Successfully adding the DetectPort; -1 on failure.
1389 */
1391{
1392 int ret = HashListTableAdd(de_ctx->dport_hash_table, (void *)dp, 0);
1393 return ret;
1394}
1395
1396/**
1397 * \brief Used to lookup a DetectPort hash from the detection engine context
1398 * DetectPort hash table.
1399 *
1400 * \param de_ctx Pointer to the detection engine context.
1401 * \param sgh Pointer to the DetectPort.
1402 *
1403 * \retval rsgh On success a pointer to the DetectPort if the DetectPort is
1404 * found in the hash table; NULL on failure.
1405 */
1407{
1408 SCEnter();
1409
1410 DetectPort *rdp = HashListTableLookup(de_ctx->dport_hash_table, (void *)dp, 0);
1411
1412 SCReturnPtr(rdp, "DetectPort");
1413}
1414
1415/**
1416 * \brief Frees the hash table - DetectEngineCtx->sgh_hash_table, allocated by
1417 * DetectPortInit() function.
1418 *
1419 * \param de_ctx Pointer to the detection engine context.
1420 */
1422{
1423 if (de_ctx->sgh_hash_table == NULL)
1424 return;
1425
1427 de_ctx->dport_hash_table = NULL;
1428}
1429
1430/*---------------------- Unittests -------------------------*/
1431
1432#ifdef UNITTESTS
1433#include "packet.h"
1434
1435/**
1436 * \brief Do a sorted insert, where the top of the list should be the biggest
1437 * port range.
1438 *
1439 * \todo XXX current sorting only works for overlapping ranges
1440 *
1441 * \param head Pointer to the DetectPort list head
1442 * \param dp Pointer to DetectPort to search in the DetectPort list
1443 * \retval 0 if dp is added correctly
1444 */
1445static int PortTestDetectPortAdd(DetectPort **head, DetectPort *dp)
1446{
1447 DetectPort *cur, *prev_cur = NULL;
1448
1449 //SCLogDebug("DetectPortAdd: adding "); DetectPortPrint(ag); SCLogDebug("");
1450
1451 if (*head != NULL) {
1452 for (cur = *head; cur != NULL; cur = cur->next) {
1453 prev_cur = cur;
1454 int r = DetectPortCmp(dp,cur);
1455 if (r == PORT_EB) {
1456 /* insert here */
1457 dp->prev = cur->prev;
1458 dp->next = cur;
1459
1460 cur->prev = dp;
1461 if (*head == cur) {
1462 *head = dp;
1463 } else {
1464 dp->prev->next = dp;
1465 }
1466 return 0;
1467 }
1468 }
1469 dp->prev = prev_cur;
1470 if (prev_cur != NULL)
1471 prev_cur->next = dp;
1472 } else {
1473 *head = dp;
1474 }
1475
1476 return 0;
1477}
1478
1479
1480/**
1481 * \test Check if a DetectPort is properly allocated
1482 */
1483static int PortTestParse01 (void)
1484{
1485 DetectPort *dd = NULL;
1486 int r = DetectPortParse(NULL,&dd,"80");
1487 FAIL_IF_NOT(r == 0);
1488 DetectPortFree(NULL, dd);
1489 PASS;
1490}
1491
1492/**
1493 * \test Check if two ports are properly allocated in the DetectPort group
1494 */
1495static int PortTestParse02 (void)
1496{
1497 DetectPort *dd = NULL;
1498 int r = DetectPortParse(NULL,&dd,"80");
1499 FAIL_IF_NOT(r == 0);
1500 r = DetectPortParse(NULL,&dd,"22");
1501 FAIL_IF_NOT(r == 0);
1502 DetectPortCleanupList(NULL, dd);
1503 PASS;
1504}
1505
1506/**
1507 * \test Check if two port ranges are properly allocated in the DetectPort group
1508 */
1509static int PortTestParse03 (void)
1510{
1511 DetectPort *dd = NULL;
1512 int r = DetectPortParse(NULL,&dd,"80:88");
1513 FAIL_IF_NOT(r == 0);
1514 r = DetectPortParse(NULL,&dd,"85:100");
1515 FAIL_IF_NOT(r == 0);
1516 DetectPortCleanupList(NULL, dd);
1517 PASS;
1518}
1519
1520/**
1521 * \test Check if a negated port range is properly allocated in the DetectPort
1522 */
1523static int PortTestParse04 (void)
1524{
1525 DetectPort *dd = NULL;
1526 int r = DetectPortParse(NULL,&dd,"!80:81");
1527 FAIL_IF_NOT(r == 0);
1528 DetectPortCleanupList(NULL, dd);
1529 PASS;
1530}
1531
1532/**
1533 * \test Check if a negated port range is properly fragmented in the allowed
1534 * real groups, ex !80:81 should allow 0:79 and 82:65535
1535 */
1536static int PortTestParse05 (void)
1537{
1538 DetectPort *dd = NULL;
1539 int r = DetectPortParse(NULL,&dd,"!80:81");
1540 FAIL_IF_NOT(r == 0);
1541 FAIL_IF_NULL(dd->next);
1542 FAIL_IF_NOT(dd->port == 0);
1543 FAIL_IF_NOT(dd->port2 == 79);
1544 FAIL_IF_NOT(dd->next->port == 82);
1545 FAIL_IF_NOT(dd->next->port2 == 65535);
1546 DetectPortCleanupList(NULL, dd);
1547 PASS;
1548}
1549
1550/**
1551 * \test Check if a negated port range is properly fragmented in the allowed
1552 * real groups
1553 */
1554static int PortTestParse07 (void)
1555{
1556 DetectPort *dd = NULL;
1557
1558 int r = DetectPortParse(NULL,&dd,"!21:902");
1559 FAIL_IF_NOT(r == 0);
1560 FAIL_IF_NULL(dd->next);
1561
1562 FAIL_IF_NOT(dd->port == 0);
1563 FAIL_IF_NOT(dd->port2 == 20);
1564 FAIL_IF_NOT(dd->next->port == 903);
1565 FAIL_IF_NOT(dd->next->port2 == 65535);
1566
1567 DetectPortCleanupList(NULL, dd);
1568 PASS;
1569}
1570
1571/**
1572 * \test Check if we dont allow invalid port range specification
1573 */
1574static int PortTestParse08 (void)
1575{
1576 DetectPort *dd = NULL;
1577
1578 int r = DetectPortParse(NULL,&dd,"[80:!80]");
1579 FAIL_IF(r == 0);
1580
1581 DetectPortCleanupList(NULL, dd);
1582 PASS;
1583}
1584
1585/**
1586 * \test Check if we autocomplete correctly an open range
1587 */
1588static int PortTestParse09 (void)
1589{
1590 DetectPort *dd = NULL;
1591
1592 int r = DetectPortParse(NULL,&dd,"1024:");
1593 FAIL_IF_NOT(r == 0);
1594 FAIL_IF_NULL(dd);
1595
1596 FAIL_IF_NOT(dd->port == 1024);
1597 FAIL_IF_NOT(dd->port2 == 0xffff);
1598
1599 DetectPortCleanupList(NULL, dd);
1600 PASS;
1601}
1602
1603/**
1604 * \test Test we don't allow a port that is too big
1605 */
1606static int PortTestParse10 (void)
1607{
1608 DetectPort *dd = NULL;
1609 int r = DetectPortParse(NULL,&dd,"77777777777777777777777777777777777777777777");
1610 FAIL_IF(r == 0);
1611 PASS;
1612}
1613
1614/**
1615 * \test Test second port of range being too big
1616 */
1617static int PortTestParse11 (void)
1618{
1619 DetectPort *dd = NULL;
1620
1621 int r = DetectPortParse(NULL,&dd,"1024:65536");
1622 FAIL_IF(r == 0);
1623 PASS;
1624}
1625
1626/**
1627 * \test Test second port of range being just right
1628 */
1629static int PortTestParse12 (void)
1630{
1631 DetectPort *dd = NULL;
1632 int r = DetectPortParse(NULL,&dd,"1024:65535");
1633 FAIL_IF_NOT(r == 0);
1634 DetectPortFree(NULL, dd);
1635 PASS;
1636}
1637
1638/**
1639 * \test Test first port of range being too big
1640 */
1641static int PortTestParse13 (void)
1642{
1643 DetectPort *dd = NULL;
1644 int r = DetectPortParse(NULL,&dd,"65536:65535");
1645 FAIL_IF(r == 0);
1646 PASS;
1647}
1648
1649/**
1650 * \test Test merging port groups
1651 */
1652static int PortTestParse14 (void)
1653{
1654 DetectPort *dd = NULL;
1655
1656 int r = DetectPortParseInsertString(NULL, &dd, "0:100");
1657 FAIL_IF_NOT(r == 0);
1658 r = DetectPortParseInsertString(NULL, &dd, "1000:65535");
1659 FAIL_IF_NOT(r == 0);
1660 FAIL_IF_NULL(dd->next);
1661
1662 FAIL_IF_NOT(dd->port == 0);
1663 FAIL_IF_NOT(dd->port2 == 100);
1664 FAIL_IF_NOT(dd->next->port == 1000);
1665 FAIL_IF_NOT(dd->next->port2 == 65535);
1666
1667 DetectPortCleanupList(NULL, dd);
1668 PASS;
1669}
1670
1671/**
1672 * \test Test merging negated port groups
1673 */
1674static int PortTestParse15 (void)
1675{
1676 DetectPort *dd = NULL;
1677
1678 int r = DetectPortParse(NULL,&dd,"![0:100,1000:3000]");
1679 FAIL_IF_NOT(r == 0);
1680 FAIL_IF_NULL(dd->next);
1681
1682 FAIL_IF_NOT(dd->port == 101);
1683 FAIL_IF_NOT(dd->port2 == 999);
1684 FAIL_IF_NOT(dd->next->port == 3001);
1685 FAIL_IF_NOT(dd->next->port2 == 65535);
1686
1687 DetectPortCleanupList(NULL, dd);
1688 PASS;
1689}
1690
1691static int PortTestParse16 (void)
1692{
1693 DetectPort *dd = NULL;
1694 int r = DetectPortParse(NULL,&dd,"\
1695[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\
16961:65535\
1697]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\
1698");
1699 FAIL_IF_NOT(r == 0);
1700 DetectPortFree(NULL, dd);
1701 dd = NULL;
1702 r = DetectPortParse(NULL,&dd,"\
1703[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\
17041:65535\
1705]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\
1706");
1707 FAIL_IF(r == 0);
1708 PASS;
1709}
1710
1711/**
1712 * \test Test general functions
1713 */
1714static int PortTestFunctions01(void)
1715{
1716 DetectPort *head = NULL;
1717 DetectPort *dp1= NULL;
1718 int result = 0;
1719
1720 /* Parse */
1721 int r = DetectPortParse(NULL,&head,"![0:100,1000:65535]");
1722 if (r != 0 || head->next != NULL)
1723 goto end;
1724
1725 /* We should have only one DetectPort */
1726 if (!(head->port == 101))
1727 goto end;
1728 if (!(head->port2 == 999))
1729 goto end;
1730 if (!(head->next == NULL))
1731 goto end;
1732
1733 r = DetectPortParse(NULL, &dp1,"2000:3000");
1734 if (r != 0 || dp1->next != NULL)
1735 goto end;
1736 if (!(dp1->port == 2000))
1737 goto end;
1738 if (!(dp1->port2 == 3000))
1739 goto end;
1740
1741 /* Add */
1742 r = PortTestDetectPortAdd(&head, dp1);
1743 if (r != 0 || head->next == NULL)
1744 goto end;
1745 if (!(head->port == 101))
1746 goto end;
1747 if (!(head->port2 == 999))
1748 goto end;
1749 if (!(head->next->port == 2000))
1750 goto end;
1751 if (!(head->next->port2 == 3000))
1752 goto end;
1753
1754 /* Match */
1755 if (!DetectPortMatch(head, 150))
1756 goto end;
1757 if (DetectPortMatch(head->next, 1500))
1758 goto end;
1759 if ((DetectPortMatch(head, 3500)))
1760 goto end;
1761 if ((DetectPortMatch(head, 50)))
1762 goto end;
1763
1764 result = 1;
1765end:
1766 if (dp1 != NULL)
1767 DetectPortFree(NULL, dp1);
1768 if (head != NULL)
1769 DetectPortFree(NULL, head);
1770 return result;
1771}
1772
1773/**
1774 * \test Test general functions
1775 */
1776static int PortTestFunctions02(void)
1777{
1778 DetectPort *head = NULL;
1779 DetectPort *dp1= NULL;
1780 DetectPort *dp2= NULL;
1781 int result = 0;
1782
1783 /* Parse */
1784 int r = DetectPortParse(NULL,&head, "![0:100,1000:65535]");
1785 if (r != 0 || head->next != NULL)
1786 goto end;
1787
1788 r = DetectPortParse(NULL, &dp1, "!200:300");
1789 if (r != 0 || dp1->next == NULL)
1790 goto end;
1791
1792 /* Merge Nots */
1793 r = DetectPortParseMergeNotPorts(NULL, &head, &dp1);
1794 if (r != 0 || head->next != NULL)
1795 goto end;
1796
1797 r = DetectPortParse(NULL, &dp2, "!100:500");
1798 if (r != 0 || dp2->next == NULL)
1799 goto end;
1800
1801 /* Merge Nots */
1802 r = DetectPortParseMergeNotPorts(NULL, &head, &dp2);
1803 if (r != 0 || head->next != NULL)
1804 goto end;
1805
1806 if (!(head->port == 200))
1807 goto end;
1808 if (!(head->port2 == 300))
1809 goto end;
1810
1811 result = 1;
1812
1813end:
1814 if (dp1 != NULL)
1815 DetectPortFree(NULL, dp1);
1816 if (dp2 != NULL)
1817 DetectPortFree(NULL, dp2);
1818 if (head != NULL)
1819 DetectPortFree(NULL, head);
1820 return result;
1821}
1822
1823/**
1824 * \test Test general functions
1825 */
1826static int PortTestFunctions03(void)
1827{
1828 DetectPort *dp1= NULL;
1829 DetectPort *dp2= NULL;
1830 DetectPort *dp3= NULL;
1831 int result = 0;
1832
1833 int r = DetectPortParse(NULL, &dp1, "200:300");
1834 if (r != 0)
1835 goto end;
1836
1837 r = DetectPortParse(NULL, &dp2, "250:300");
1838 if (r != 0)
1839 goto end;
1840
1841 /* Cut */
1842 DetectPortCut(NULL, dp1, dp2, &dp3);
1843 if (r != 0)
1844 goto end;
1845
1846 if (!(dp1->port == 200))
1847 goto end;
1848 if (!(dp1->port2 == 249))
1849 goto end;
1850 if (!(dp2->port == 250))
1851 goto end;
1852 if (!(dp2->port2 == 300))
1853 goto end;
1854
1855 dp1->port = 0;
1856 dp1->port2 = 500;
1857 dp2->port = 250;
1858 dp2->port2 = 750;
1859
1860 /* Cut */
1861 DetectPortCut(NULL, dp1, dp2, &dp3);
1862 if (r != 0)
1863 goto end;
1864 if (!(dp1->port == 0))
1865 goto end;
1866 if (!(dp1->port2 == 249))
1867 goto end;
1868 if (!(dp2->port == 250))
1869 goto end;
1870 if (!(dp2->port2 == 500))
1871 goto end;
1872 if (!(dp3->port == 501))
1873 goto end;
1874 if (!(dp3->port2 == 750))
1875 goto end;
1876
1877 result = 1;
1878
1879end:
1880 if (dp1 != NULL)
1881 DetectPortFree(NULL, dp1);
1882 if (dp2 != NULL)
1883 DetectPortFree(NULL, dp2);
1884 if (dp3 != NULL)
1885 DetectPortFree(NULL, dp3);
1886 return result;
1887}
1888
1889/**
1890 * \test Test general functions
1891 */
1892static int PortTestFunctions04(void)
1893{
1894 DetectPort *dp1= NULL;
1895 DetectPort *dp2= NULL;
1896 int result = 0;
1897
1898 int r = DetectPortParse(NULL, &dp1, "200:300");
1899 if (r != 0)
1900 goto end;
1901
1902 dp2 = DetectPortInit();
1903
1904 /* Cut Not */
1905 DetectPortCutNot(dp1, &dp2);
1906 if (r != 0)
1907 goto end;
1908
1909 if (!(dp1->port == 0))
1910 goto end;
1911 if (!(dp1->port2 == 199))
1912 goto end;
1913 if (!(dp2->port == 301))
1914 goto end;
1915 if (!(dp2->port2 == 65535))
1916 goto end;
1917
1918 result = 1;
1919end:
1920 if (dp1 != NULL)
1921 DetectPortFree(NULL, dp1);
1922 if (dp2 != NULL)
1923 DetectPortFree(NULL, dp2);
1924 return result;
1925}
1926
1927/**
1928 * \test Test general functions
1929 */
1930static int PortTestFunctions07(void)
1931{
1932 DetectPort *dd = NULL;
1933
1934 // This one should fail due to negation in a range
1935 FAIL_IF(DetectPortParse(NULL, &dd, "[80:!99]") == 0);
1936
1937 // Correct: from 80 till 100 but 99 excluded
1938 FAIL_IF_NOT(DetectPortParse(NULL, &dd, "[80:100,!99]") == 0);
1939 FAIL_IF_NULL(dd->next);
1940 FAIL_IF_NOT(dd->port == 80);
1941 FAIL_IF_NOT(dd->port2 == 98);
1942 FAIL_IF_NOT(dd->next->port == 100);
1943
1944 // Also good: from 1 till 80 except of 2 and 4
1945 FAIL_IF_NOT(DetectPortParse(NULL, &dd, "[1:80,![2,4]]") == 0);
1946 FAIL_IF_NOT(dd->port == 1);
1950
1951 DetectPortCleanupList(NULL, dd);
1952 PASS;
1953}
1954
1955/**
1956 * \test Test packet Matches
1957 * \param raw_eth_pkt pointer to the ethernet packet
1958 * \param pktsize size of the packet
1959 * \param sig pointer to the signature to test
1960 * \param sid sid number of the signature
1961 * \retval return 1 if match
1962 * \retval return 0 if not
1963 */
1964static int PortTestMatchReal(uint8_t *raw_eth_pkt, uint16_t pktsize, const char *sig,
1965 uint32_t sid)
1966{
1967 int result = 0;
1969 Packet *p = UTHBuildPacketFromEth(raw_eth_pkt, pktsize);
1970 result = UTHPacketMatchSig(p, sig);
1971 PacketRecycle(p);
1972 FlowShutdown();
1973 return result;
1974}
1975
1976/**
1977 * \brief Wrapper for PortTestMatchReal
1978 */
1979static int PortTestMatchRealWrp(const char *sig, uint32_t sid)
1980{
1981 /* Real HTTP packeth doing a GET method
1982 * tcp.sport=47370 tcp.dport=80
1983 * ip.src=192.168.28.131 ip.dst=192.168.1.1
1984 */
1985 uint8_t raw_eth_pkt[] = {
1986 0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
1987 0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
1988 0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
1989 0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
1990 0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
1991 0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
1992 0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
1993 0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
1994 0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
1995 0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
1996 0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
1997 0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
1998 0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
1999 0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
2000 0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
2001 0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
2002 0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
2003 0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
2004 0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
2005 0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
2006 0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
2007 0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
2008 0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
2009 0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
2010 0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
2011 0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
2012 0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
2013 0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
2014 0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
2015 0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
2016 0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
2017 0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
2018 0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
2019 0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
2020 0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
2021 0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
2022 0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
2023 0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
2024 0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
2025 0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
2026 0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
2027 0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
2028 0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
2029 0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
2030 0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
2031 0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
2032 0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
2033 0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
2034 0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
2035 0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
2036 0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
2037 0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
2038 0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
2039 0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
2040 0x76,0x65,0x0d,0x0a,0x0d,0x0a };
2041 /* end raw_eth_pkt */
2042
2043 return PortTestMatchReal(raw_eth_pkt, (uint16_t)sizeof(raw_eth_pkt),
2044 sig, sid);
2045}
2046
2047/**
2048 * \test Check if we match a dest port
2049 */
2050static int PortTestMatchReal01(void)
2051{
2052 /* tcp.sport=47370 tcp.dport=80 */
2053 const char *sig = "alert tcp any any -> any 80 (msg:\"Nothing..\"; content:\"GET\"; sid:1;)";
2054 return PortTestMatchRealWrp(sig, 1);
2055}
2056
2057/**
2058 * \test Check if we match a source port
2059 */
2060static int PortTestMatchReal02(void)
2061{
2062 const char *sig = "alert tcp any 47370 -> any any (msg:\"Nothing..\";"
2063 " content:\"GET\"; sid:1;)";
2064 return PortTestMatchRealWrp(sig, 1);
2065}
2066
2067/**
2068 * \test Check if we match both of them
2069 */
2070static int PortTestMatchReal03(void)
2071{
2072 const char *sig = "alert tcp any 47370 -> any 80 (msg:\"Nothing..\";"
2073 " content:\"GET\"; sid:1;)";
2074 return PortTestMatchRealWrp(sig, 1);
2075}
2076
2077/**
2078 * \test Check if we negate dest ports correctly
2079 */
2080static int PortTestMatchReal04(void)
2081{
2082 const char *sig = "alert tcp any any -> any !80 (msg:\"Nothing..\";"
2083 " content:\"GET\"; sid:1;)";
2084 return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
2085}
2086
2087/**
2088 * \test Check if we negate source ports correctly
2089 */
2090static int PortTestMatchReal05(void)
2091{
2092 const char *sig = "alert tcp any !47370 -> any any (msg:\"Nothing..\";"
2093 " content:\"GET\"; sid:1;)";
2094 return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
2095}
2096
2097/**
2098 * \test Check if we negate both ports correctly
2099 */
2100static int PortTestMatchReal06(void)
2101{
2102 const char *sig = "alert tcp any !47370 -> any !80 (msg:\"Nothing..\";"
2103 " content:\"GET\"; sid:1;)";
2104 return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
2105}
2106
2107/**
2108 * \test Check if we match a dest port range
2109 */
2110static int PortTestMatchReal07(void)
2111{
2112 const char *sig = "alert tcp any any -> any 70:100 (msg:\"Nothing..\";"
2113 " content:\"GET\"; sid:1;)";
2114 return PortTestMatchRealWrp(sig, 1);
2115}
2116
2117/**
2118 * \test Check if we match a source port range
2119 */
2120static int PortTestMatchReal08(void)
2121{
2122 const char *sig = "alert tcp any 47000:50000 -> any any (msg:\"Nothing..\";"
2123 " content:\"GET\"; sid:1;)";
2124 return PortTestMatchRealWrp(sig, 1);
2125}
2126
2127/**
2128 * \test Check if we match both port ranges
2129 */
2130static int PortTestMatchReal09(void)
2131{
2132 const char *sig = "alert tcp any 47000:50000 -> any 70:100 (msg:\"Nothing..\";"
2133 " content:\"GET\"; sid:1;)";
2134 return PortTestMatchRealWrp(sig, 1);
2135}
2136
2137/**
2138 * \test Check if we negate a dest port range
2139 */
2140static int PortTestMatchReal10(void)
2141{
2142 const char *sig = "alert tcp any any -> any !70:100 (msg:\"Nothing..\";"
2143 " content:\"GET\"; sid:1;)";
2144 return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
2145}
2146
2147/**
2148 * \test Check if we negate a source port range
2149 */
2150static int PortTestMatchReal11(void)
2151{
2152 const char *sig = "alert tcp any !47000:50000 -> any any (msg:\"Nothing..\";"
2153 " content:\"GET\"; sid:1;)";
2154 return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
2155}
2156
2157/**
2158 * \test Check if we negate both port ranges
2159 */
2160static int PortTestMatchReal12(void)
2161{
2162 const char *sig = "alert tcp any !47000:50000 -> any !70:100 (msg:\"Nothing..\";"
2163 " content:\"GET\"; sid:1;)";
2164 return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
2165}
2166
2167/**
2168 * \test Check if we autocomplete ranges correctly
2169 */
2170static int PortTestMatchReal13(void)
2171{
2172 const char *sig = "alert tcp any 47000:50000 -> any !81: (msg:\"Nothing..\";"
2173 " content:\"GET\"; sid:1;)";
2174 return PortTestMatchRealWrp(sig, 1);
2175}
2176
2177/**
2178 * \test Check if we autocomplete ranges correctly
2179 */
2180static int PortTestMatchReal14(void)
2181{
2182 const char *sig = "alert tcp any !48000:50000 -> any :100 (msg:\"Nothing..\";"
2183 " content:\"GET\"; sid:1;)";
2184 return PortTestMatchRealWrp(sig, 1);
2185}
2186
2187/**
2188 * \test Check if we autocomplete ranges correctly
2189 */
2190static int PortTestMatchReal15(void)
2191{
2192 const char *sig = "alert tcp any :50000 -> any 81:100 (msg:\"Nothing..\";"
2193 " content:\"GET\"; sid:1;)";
2194 return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
2195}
2196
2197/**
2198 * \test Check if we separate ranges correctly
2199 */
2200static int PortTestMatchReal16(void)
2201{
2202 const char *sig = "alert tcp any 100: -> any ![0:79,81:65535] (msg:\"Nothing..\";"
2203 " content:\"GET\"; sid:1;)";
2204 return PortTestMatchRealWrp(sig, 1);
2205}
2206
2207/**
2208 * \test Check if we separate ranges correctly
2209 */
2210static int PortTestMatchReal17(void)
2211{
2212 const char *sig = "alert tcp any ![0:39999,48000:50000] -> any ![0:80,82:65535] "
2213 "(msg:\"Nothing..\"; content:\"GET\"; sid:1;)";
2214 return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
2215}
2216
2217/**
2218 * \test Check if we separate ranges correctly
2219 */
2220static int PortTestMatchReal18(void)
2221{
2222 const char *sig = "alert tcp any ![0:39999,48000:50000] -> any 80 (msg:\"Nothing"
2223 " at all\"; content:\"GET\"; sid:1;)";
2224 return PortTestMatchRealWrp(sig, 1);
2225}
2226
2227/**
2228 * \test Check if we separate ranges correctly
2229 */
2230static int PortTestMatchReal19(void)
2231{
2232 const char *sig = "alert tcp any any -> any 80 (msg:\"Nothing..\";"
2233 " content:\"GET\"; sid:1;)";
2234 return PortTestMatchRealWrp(sig, 1);
2235}
2236
2237static int PortTestMatchDoubleNegation(void)
2238{
2239 int result = 0;
2240 DetectPort *head = NULL, *nhead = NULL;
2241
2242 if (DetectPortParseDo(NULL, &head, &nhead, "![!80]", 0, NULL, 0) == -1)
2243 return result;
2244
2245 result = (head != NULL);
2246 result = (nhead == NULL);
2247
2248 return result;
2249}
2250
2251// Test that negation is successfully parsed with whitespace for port strings of
2252// length < 16
2253static int DetectPortParseDoTest(void)
2254{
2257 DetectPort *head = NULL;
2258 DetectPort *nhead = NULL;
2259 const char *str = "[30:50, !45]";
2260 int r = DetectPortParseDo(de_ctx, &head, &nhead, str, 0, NULL, 0);
2261
2262 // Assertions
2264 FAIL_IF_NULL(nhead);
2265 FAIL_IF(r < 0);
2266 FAIL_IF(head->port != 30);
2267 FAIL_IF(head->port2 != 50);
2268 FAIL_IF(nhead->port != 45);
2269 FAIL_IF(nhead->port2 != 45);
2271 DetectPortCleanupList(NULL, nhead);
2272 PASS;
2273}
2274
2275static int DetectPortParseDoTest2(void)
2276{
2279 DetectPort *head = NULL;
2280 DetectPort *nhead = NULL;
2281 const char *str = "[30:50, !45]";
2282 int r = DetectPortParseDo(de_ctx, &head, &nhead, str, 0, NULL, 0);
2283 FAIL_IF(r < 0);
2285 DetectPortCleanupList(NULL, nhead);
2286 PASS;
2287}
2288
2289// Verifies correct parsing when negation port string length < 16
2290static int PortParseTestLessThan14Spaces(void)
2291{
2292 const char *str = " 45";
2293 DetectPort *dp = PortParse(str);
2294 FAIL_IF_NULL(dp);
2295 FAIL_IF(dp->port != 45);
2296 FAIL_IF(dp->port2 != 45);
2297 DetectPortFree(NULL, dp);
2298 PASS;
2299}
2300
2301// Verifies NULL returned when negation port string length == 16
2302static int PortParseTest14Spaces(void)
2303{
2304 const char *str = " 45";
2305 DetectPort *dp = PortParse(str);
2306 FAIL_IF_NULL(dp);
2307 FAIL_IF(dp->port != 45);
2308 FAIL_IF(dp->port2 != 45);
2309 DetectPortFree(NULL, dp);
2310 PASS;
2311}
2312
2313// Verifies NULL returned when negation port string length >= 16
2314static int PortParseTestMoreThan14Spaces(void)
2315{
2316 const char *str = " 45";
2317 DetectPort *dp = PortParse(str);
2318 FAIL_IF_NULL(dp);
2319 FAIL_IF(dp->port != 45);
2320 FAIL_IF(dp->port2 != 45);
2321 DetectPortFree(NULL, dp);
2322 PASS;
2323}
2324
2326{
2327 UtRegisterTest("PortTestParse01", PortTestParse01);
2328 UtRegisterTest("PortTestParse02", PortTestParse02);
2329 UtRegisterTest("PortTestParse03", PortTestParse03);
2330 UtRegisterTest("PortTestParse04", PortTestParse04);
2331 UtRegisterTest("PortTestParse05", PortTestParse05);
2332 UtRegisterTest("PortTestParse07", PortTestParse07);
2333 UtRegisterTest("PortTestParse08", PortTestParse08);
2334 UtRegisterTest("PortTestParse09", PortTestParse09);
2335 UtRegisterTest("PortTestParse10", PortTestParse10);
2336 UtRegisterTest("PortTestParse11", PortTestParse11);
2337 UtRegisterTest("PortTestParse12", PortTestParse12);
2338 UtRegisterTest("PortTestParse13", PortTestParse13);
2339 UtRegisterTest("PortTestParse14", PortTestParse14);
2340 UtRegisterTest("PortTestParse15", PortTestParse15);
2341 UtRegisterTest("PortTestParse16", PortTestParse16);
2342 UtRegisterTest("PortTestFunctions01", PortTestFunctions01);
2343 UtRegisterTest("PortTestFunctions02", PortTestFunctions02);
2344 UtRegisterTest("PortTestFunctions03", PortTestFunctions03);
2345 UtRegisterTest("PortTestFunctions04", PortTestFunctions04);
2346 UtRegisterTest("PortTestFunctions07", PortTestFunctions07);
2347 UtRegisterTest("PortTestMatchReal01", PortTestMatchReal01);
2348 UtRegisterTest("PortTestMatchReal02", PortTestMatchReal02);
2349 UtRegisterTest("PortTestMatchReal03", PortTestMatchReal03);
2350 UtRegisterTest("PortTestMatchReal04", PortTestMatchReal04);
2351 UtRegisterTest("PortTestMatchReal05", PortTestMatchReal05);
2352 UtRegisterTest("PortTestMatchReal06", PortTestMatchReal06);
2353 UtRegisterTest("PortTestMatchReal07", PortTestMatchReal07);
2354 UtRegisterTest("PortTestMatchReal08", PortTestMatchReal08);
2355 UtRegisterTest("PortTestMatchReal09", PortTestMatchReal09);
2356 UtRegisterTest("PortTestMatchReal10", PortTestMatchReal10);
2357 UtRegisterTest("PortTestMatchReal11", PortTestMatchReal11);
2358 UtRegisterTest("PortTestMatchReal12", PortTestMatchReal12);
2359 UtRegisterTest("PortTestMatchReal13", PortTestMatchReal13);
2360 UtRegisterTest("PortTestMatchReal14", PortTestMatchReal14);
2361 UtRegisterTest("PortTestMatchReal15", PortTestMatchReal15);
2362 UtRegisterTest("PortTestMatchReal16", PortTestMatchReal16);
2363 UtRegisterTest("PortTestMatchReal17", PortTestMatchReal17);
2364 UtRegisterTest("PortTestMatchReal18", PortTestMatchReal18);
2365 UtRegisterTest("PortTestMatchReal19", PortTestMatchReal19);
2366 UtRegisterTest("PortTestMatchDoubleNegation", PortTestMatchDoubleNegation);
2367 UtRegisterTest("DetectPortParseDoTest", DetectPortParseDoTest);
2368 UtRegisterTest("DetectPortParseDoTest2", DetectPortParseDoTest2);
2369 UtRegisterTest("PortParseTestLessThan14Spaces", PortParseTestLessThan14Spaces);
2370 UtRegisterTest("PortParseTest14Spaces", PortParseTest14Spaces);
2371 UtRegisterTest("PortParseTestMoreThan14Spaces", PortParseTestMoreThan14Spaces);
2372}
2373
2374#endif /* UNITTESTS */
uint16_t dst
uint16_t src
struct HtpBodyChunk_ * next
SCConfNode * SCConfGetNode(const char *name)
Get a SCConfNode by name.
Definition conf.c:181
int DetectPortInsert(DetectEngineCtx *de_ctx, DetectPort **head, DetectPort *new)
function for inserting a port group object. This also makes sure SigGroupContainer lists are handled ...
DetectPort * DetectPortInit(void)
Alloc a DetectPort structure and update counters.
int DetectPortParse(const DetectEngineCtx *de_ctx, DetectPort **head, const char *str)
Function for parsing port strings.
DetectPort * DetectPortCopySingle(DetectEngineCtx *de_ctx, DetectPort *src)
Function that return a copy of DetectPort src sigs.
DetectPort * DetectPortLookupGroup(DetectPort *dp, uint16_t port)
Function that find the group matching port in a group head.
void DetectPortPrintList(DetectPort *head)
Helper function used to print the list of ports present in this DetectPort list.
void DetectPortPrint(DetectPort *dp)
Helper function that print the DetectPort info.
void DetectPortTests(void)
DetectPort * PortParse(const char *str)
Helper function for parsing port strings.
void DetectPortCleanupList(const DetectEngineCtx *de_ctx, DetectPort *head)
Free a DetectPort list and each of its members.
bool DetectPortListsAreEqual(DetectPort *list1, DetectPort *list2)
Checks if two port group lists are equal.
int DetectPortCmp(DetectPort *a, DetectPort *b)
Function that compare port groups.
int DetectPortTestConfVars(void)
DetectPort * DetectPortHashLookup(DetectEngineCtx *de_ctx, DetectPort *dp)
Used to lookup a DetectPort hash from the detection engine context DetectPort hash table.
void DetectPortHashFree(DetectEngineCtx *de_ctx)
Frees the hash table - DetectEngineCtx->sgh_hash_table, allocated by DetectPortInit() function.
void DetectPortFree(const DetectEngineCtx *de_ctx, DetectPort *dp)
Free a DetectPort and its members.
int DetectPortHashAdd(DetectEngineCtx *de_ctx, DetectPort *dp)
Adds a DetectPort to the detection engine context DetectPort hash table.
int DetectPortHashInit(DetectEngineCtx *de_ctx)
Initializes the hash table in the detection engine context to hold the DetectPort hash.
int SigGroupHeadCopySigs(DetectEngineCtx *de_ctx, SigGroupHead *src, SigGroupHead **dst)
Copies the bitarray holding the sids from the source SigGroupHead to the destination SigGroupHead.
void SigGroupHeadFree(const DetectEngineCtx *de_ctx, SigGroupHead *sgh)
Free a SigGroupHead and its members.
DetectEngineCtx * DetectEngineCtxInit(void)
#define PORT_FLAG_NOT
Definition detect.h:216
#define PORT_FLAG_ANY
Definition detect.h:215
#define PORT_SIGGROUPHEAD_COPY
Definition detect.h:217
@ PORT_GE
Definition detect.h:211
@ PORT_EB
Definition detect.h:210
@ PORT_GT
Definition detect.h:212
@ PORT_EQ
Definition detect.h:208
@ PORT_LE
Definition detect.h:207
@ PORT_ER
Definition detect.h:205
@ PORT_LT
Definition detect.h:206
@ PORT_ES
Definition detect.h:209
Flow * head
Definition flow-hash.h:1
void FlowInitConfig(bool quiet)
initialize the configuration
Definition flow.c:547
void FlowShutdown(void)
shutdown the flow engine
Definition flow.c:691
#define FLOW_QUIET
Definition flow.h:43
DetectEngineCtx * de_ctx
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
#define PASS
Pass the test.
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
void PacketRecycle(Packet *p)
Definition packet.c:150
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:252
#define TAILQ_HEAD_INITIALIZER(head)
Definition queue.h:236
main detection engine ctx
Definition detect.h:932
HashListTable * dport_hash_table
Definition detect.h:1066
HashListTable * sgh_hash_table
Definition detect.h:962
Port structure for detection engine.
Definition detect.h:220
uint16_t port
Definition detect.h:221
uint16_t port2
Definition detect.h:222
struct DetectPort_ * next
Definition detect.h:234
struct DetectPort_ * prev
Definition detect.h:233
struct SigGroupHead_ * sh
Definition detect.h:231
uint8_t flags
Definition detect.h:224
struct Flow_ * next
Definition flow.h:396
uint32_t array_size
char * name
Definition conf.h:38
char * val
Definition conf.h:39
#define BUG_ON(x)
#define str(s)
size_t strlcpy(char *dst, const char *src, size_t siz)
uint32_t cnt
int StringParseUint16(uint16_t *res, int base, size_t len, const char *str)
Definition util-byte.c:337
int SCLogDebugEnabled(void)
Returns whether debug messages are enabled to be logged or not.
Definition util-debug.c:767
#define SCEnter(...)
Definition util-debug.h:277
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCReturnPtr(x, type)
Definition util-debug.h:293
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
void * HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen)
int HashListTableAdd(HashListTable *ht, void *data, uint16_t datalen)
HashListTable * HashListTableInit(uint32_t size, uint32_t(*Hash)(struct HashListTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
void HashListTableFree(HashListTable *ht)
#define SCMalloc(sz)
Definition util-mem.h:47
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define SCStrdup(s)
Definition util-mem.h:56
#define unlikely(expr)
const char * SCRuleVarsGetConfVar(const DetectEngineCtx *de_ctx, const char *conf_var_name, SCRuleVarsType conf_vars_type)
@ SC_RULE_VARS_PORT_GROUPS
int UTHPacketMatchSig(Packet *p, const char *sig)
Packet * UTHBuildPacketFromEth(uint8_t *raw_eth, uint16_t pktsize)
UTHBuildPacketFromEth is a wrapper that build a packet for the rawbytes.
void CleanVariableResolveList(ResolvedVariablesList *var_list)
Definition util-var.c:168
int AddVariableToResolveList(ResolvedVariablesList *list, const char *var)
Definition util-var.c:139