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