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  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()) {
228  DetectPortPrint(c);
229  }
230  r = DetectPortInsert(de_ctx, head, c);
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;
246 error:
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  * */
262 static 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) {
433  DetectPortFree(de_ctx, tmp);
434  }
435  return 0;
436 
437 error:
438  if (tmp != NULL)
439  DetectPortFree(de_ctx, tmp);
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  * */
452 static 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  * */
576 static 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  */
673 static 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  */
687 static 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 
743 error:
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  */
774 static 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 < 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  BUG_ON(x == 0); /* always false; added to guide static code analyzers like Coverity */
811  x--;
812  } else if (s[u] == '[') {
813  if (!o_set) {
814  o_set = 1;
815  x = 0;
816  }
817  depth++;
818  } else if (s[u] == ']') {
819  if (depth == 1) {
820  port[x - 1] = '\0';
821  SCLogDebug("Parsed port from DetectPortParseDo - %s", port);
822  x = 0;
823 
824  r = DetectPortParseDo(
825  de_ctx, head, nhead, port, negate ? negate : n_set, var_list, recur);
826  if (r == -1)
827  goto error;
828 
829  n_set = 0;
830  }
831  depth--;
832  range = 0;
833  } else if (depth == 0 && s[u] == ',') {
834  if (o_set == 1) {
835  o_set = 0;
836  } else if (d_set == 1) {
837  char *temp_rule_var_port = NULL,
838  *alloc_rule_var_port = NULL;
839 
840  port[x - 1] = '\0';
841 
842  rule_var_port = SCRuleVarsGetConfVar(de_ctx, port, SC_RULE_VARS_PORT_GROUPS);
843  if (rule_var_port == NULL)
844  goto error;
845  if (strlen(rule_var_port) == 0) {
846  SCLogError("variable %s resolved "
847  "to nothing. This is likely a misconfiguration. "
848  "Note that a negated port needs to be quoted, "
849  "\"!$HTTP_PORTS\" instead of !$HTTP_PORTS. See issue #295.",
850  s);
851  goto error;
852  }
853  if (negate == 1 || n_set == 1) {
854  /* add +1 to safisfy gcc 15 + -Wformat-truncation=2 */
855  const size_t str_size = strlen(rule_var_port) + 3 + 1;
856  alloc_rule_var_port = SCMalloc(str_size);
857  if (unlikely(alloc_rule_var_port == NULL))
858  goto error;
859  snprintf(alloc_rule_var_port, str_size, "[%s]", rule_var_port);
860  } else {
861  alloc_rule_var_port = SCStrdup(rule_var_port);
862  if (unlikely(alloc_rule_var_port == NULL))
863  goto error;
864  }
865  temp_rule_var_port = alloc_rule_var_port;
866  r = DetectPortParseDo(de_ctx, head, nhead, temp_rule_var_port,
867  (negate + n_set) % 2, var_list, recur);
868  if (r == -1) {
869  SCFree(alloc_rule_var_port);
870  goto error;
871  }
872  d_set = 0;
873  n_set = 0;
874  SCFree(alloc_rule_var_port);
875  } else {
876  port[x - 1] = '\0';
877  SCLogDebug("Parsed port from DetectPortParseDo - %s", port);
878 
879  if (negate == 0 && n_set == 0) {
880  r = DetectPortParseInsertString(de_ctx, head, port);
881  } else {
882  r = DetectPortParseInsertString(de_ctx, nhead, port);
883  }
884  if (r == -1)
885  goto error;
886 
887  n_set = 0;
888  }
889  x = 0;
890  range = 0;
891  } else if (depth == 0 && s[u] == '$') {
892  d_set = 1;
893  } else if (depth == 0 && u == size-1) {
894  range = 0;
895  if (x == 1024) {
896  port[x - 1] = '\0';
897  } else {
898  port[x] = '\0';
899  }
900  SCLogDebug("%s", port);
901 
902  if (AddVariableToResolveList(var_list, port) == -1) {
903  SCLogError("Found a loop in a port "
904  "groups declaration. This is likely a misconfiguration.");
905  goto error;
906  }
907 
908  x = 0;
909  if (d_set == 1) {
910  char *temp_rule_var_port = NULL,
911  *alloc_rule_var_port = NULL;
912 
913  rule_var_port = SCRuleVarsGetConfVar(de_ctx, port, SC_RULE_VARS_PORT_GROUPS);
914  if (rule_var_port == NULL)
915  goto error;
916  if (strlen(rule_var_port) == 0) {
917  SCLogError("variable %s resolved "
918  "to nothing. This is likely a misconfiguration. "
919  "Note that a negated port needs to be quoted, "
920  "\"!$HTTP_PORTS\" instead of !$HTTP_PORTS. See issue #295.",
921  s);
922  goto error;
923  }
924  if ((negate + n_set) % 2) {
925  /* add +1 to safisfy gcc 15 + -Wformat-truncation=2 */
926  const size_t str_size = strlen(rule_var_port) + 3 + 1;
927  alloc_rule_var_port = SCMalloc(str_size);
928  if (unlikely(alloc_rule_var_port == NULL))
929  goto error;
930  snprintf(alloc_rule_var_port, str_size, "[%s]", rule_var_port);
931  } else {
932  alloc_rule_var_port = SCStrdup(rule_var_port);
933  if (unlikely(alloc_rule_var_port == NULL))
934  goto error;
935  }
936  temp_rule_var_port = alloc_rule_var_port;
937  r = DetectPortParseDo(de_ctx, head, nhead, temp_rule_var_port,
938  (negate + n_set) % 2, var_list, recur);
939  SCFree(alloc_rule_var_port);
940  if (r == -1)
941  goto error;
942 
943  d_set = 0;
944  } else {
945  if (!((negate + n_set) % 2)) {
946  r = DetectPortParseInsertString(de_ctx, head, port);
947  } else {
948  r = DetectPortParseInsertString(de_ctx, nhead, port);
949  }
950  if (r == -1)
951  goto error;
952  }
953  n_set = 0;
954  } else if (depth == 1 && s[u] == ',') {
955  range = 0;
956  }
957  }
958 
959  if (depth > 0) {
960  SCLogError("not every port block was "
961  "properly closed in \"%s\", %d missing closing brackets (]). "
962  "Note: problem might be in a variable.",
963  s, depth);
964  goto error;
965  } else if (depth < 0) {
966  SCLogError("not every port block was "
967  "properly opened in \"%s\", %d missing opening brackets ([). "
968  "Note: problem might be in a variable.",
969  s, depth * -1);
970  goto error;
971  }
972 
973  return 0;
974 error:
975  return -1;
976 }
977 
978 /**
979  * \brief Check if the port group list covers the complete port space.
980  * \retval 0 no
981  * \retval 1 yes
982  */
983 static int DetectPortIsCompletePortSpace(DetectPort *p)
984 {
985  uint16_t next_port = 0;
986 
987  if (p == NULL)
988  return 0;
989 
990  if (p->port != 0x0000)
991  return 0;
992 
993  /* if we're ending with 0xFFFF while we know
994  we started with 0x0000 it's the complete space */
995  if (p->port2 == 0xFFFF)
996  return 1;
997 
998  next_port = p->port2 + 1;
999  p = p->next;
1000 
1001  for ( ; p != NULL; p = p->next) {
1002  if (p->port != next_port)
1003  return 0;
1004 
1005  if (p->port2 == 0xFFFF)
1006  return 1;
1007 
1008  next_port = p->port2 + 1;
1009  }
1010 
1011  return 0;
1012 }
1013 
1014 /**
1015  * \brief Helper function for the parsing process
1016  *
1017  * \param head Pointer to the head of the DetectPort group list
1018  * \param nhead Pointer to the new head of the DetectPort group list
1019  *
1020  * \retval 0 on success
1021  * \retval -1 on error
1022  */
1023 static int DetectPortParseMergeNotPorts(const DetectEngineCtx *de_ctx,
1024  DetectPort **head, DetectPort **nhead)
1025 {
1026  DetectPort *port = NULL;
1027  DetectPort *pg, *pg2;
1028  int r = 0;
1029 
1030  /** check if the full port space is negated */
1031  if (DetectPortIsCompletePortSpace(*nhead) == 1) {
1032  SCLogError("Complete port space is negated");
1033  goto error;
1034  }
1035 
1036  /**
1037  * step 0: if the head list is empty, but the nhead list isn't
1038  * we have a pure not thingy. In that case we add a 0:65535
1039  * first.
1040  */
1041  if (*head == NULL && *nhead != NULL) {
1042  SCLogDebug("inserting 0:65535 into head");
1043  r = DetectPortParseInsertString(de_ctx, head,"0:65535");
1044  if (r < 0) {
1045  goto error;
1046  }
1047  }
1048 
1049  /** step 1: insert our ghn members into the gh list */
1050  for (pg = *nhead; pg != NULL; pg = pg->next) {
1051  /** work with a copy of the port so we can easily clean up
1052  * the ghn group later.
1053  */
1054  port = DetectPortCopySingle(NULL, pg);
1055  if (port == NULL) {
1056  goto error;
1057  }
1058  r = DetectPortParseInsert(head, port);
1059  if (r < 0) {
1060  goto error;
1061  }
1062  port = NULL;
1063  }
1064 
1065  /** step 2: pull the port blocks that match our 'not' blocks */
1066  for (pg = *nhead; pg != NULL; pg = pg->next) {
1067  SCLogDebug("pg %p", pg);
1068  DetectPortPrint(pg);
1069 
1070  for (pg2 = *head; pg2 != NULL;) {
1071  SCLogDebug("pg2 %p", pg2);
1072  DetectPortPrint(pg2);
1073 
1074  r = DetectPortCmp(pg, pg2);
1075  if (r == PORT_EQ || r == PORT_EB) { /* XXX more ??? */
1076  if (pg2->prev != NULL)
1077  pg2->prev->next = pg2->next;
1078  if (pg2->next != NULL)
1079  pg2->next->prev = pg2->prev;
1080  if (*head == pg2)
1081  *head = pg2->next;
1082  /** store the next ptr and remove the group */
1083  DetectPort *next_pg2 = pg2->next;
1084  DetectPortFree(de_ctx, pg2);
1085  pg2 = next_pg2;
1086  } else {
1087  pg2 = pg2->next;
1088  }
1089  }
1090  }
1091 
1092  for (pg2 = *head; pg2 != NULL; pg2 = pg2->next) {
1093  SCLogDebug("pg2 %p", pg2);
1094  DetectPortPrint(pg2);
1095  }
1096 
1097  if (*head == NULL) {
1098  SCLogError("no ports left after merging ports with negated ports");
1099  goto error;
1100  }
1101 
1102  return 0;
1103 error:
1104  if (port != NULL)
1105  DetectPortFree(de_ctx, port);
1106  return -1;
1107 }
1108 
1110 {
1111  SCLogDebug("Testing port conf vars for any misconfigured values");
1112 
1113  ResolvedVariablesList var_list = TAILQ_HEAD_INITIALIZER(var_list);
1114 
1115  SCConfNode *port_vars_node = SCConfGetNode("vars.port-groups");
1116  if (port_vars_node == NULL) {
1117  return 0;
1118  }
1119 
1120  SCConfNode *seq_node;
1121  TAILQ_FOREACH(seq_node, &port_vars_node->head, next) {
1122  SCLogDebug("Testing %s - %s\n", seq_node->name, seq_node->val);
1123 
1124  DetectPort *gh = DetectPortInit();
1125  if (gh == NULL) {
1126  goto error;
1127  }
1128  DetectPort *ghn = NULL;
1129 
1130  if (seq_node->val == NULL) {
1131  SCLogError("Port var \"%s\" probably has a sequence(something "
1132  "in brackets) value set without any quotes. Please "
1133  "quote it using \"..\".",
1134  seq_node->name);
1135  DetectPortCleanupList(NULL, gh);
1136  goto error;
1137  }
1138 
1139  int r = DetectPortParseDo(NULL, &gh, &ghn, seq_node->val,
1140  /* start with negate no */0, &var_list, 0);
1141 
1142  CleanVariableResolveList(&var_list);
1143 
1144  if (r < 0) {
1145  DetectPortCleanupList(NULL, gh);
1146  SCLogError("failed to parse port var \"%s\" with value \"%s\". "
1147  "Please check its syntax",
1148  seq_node->name, seq_node->val);
1149  goto error;
1150  }
1151 
1152  if (DetectPortIsCompletePortSpace(ghn)) {
1153  SCLogError("Port var - \"%s\" has the complete Port range negated "
1154  "with its value \"%s\". Port space range is NIL. "
1155  "Probably have a !any or a port range that supplies "
1156  "a NULL port range",
1157  seq_node->name, seq_node->val);
1158  DetectPortCleanupList(NULL, gh);
1159  DetectPortCleanupList(NULL, ghn);
1160  goto error;
1161  }
1162 
1163  if (gh != NULL)
1164  DetectPortCleanupList(NULL, gh);
1165  if (ghn != NULL)
1166  DetectPortCleanupList(NULL, ghn);
1167  }
1168 
1169  return 0;
1170  error:
1171  return -1;
1172 }
1173 
1174 
1175 /**
1176  * \brief Function for parsing port strings
1177  *
1178  * \param de_ctx Pointer to the detection engine context
1179  * \param head Pointer to the head of the DetectPort group list
1180  * \param str Pointer to the port string
1181  *
1182  * \retval 0 on success
1183  * \retval -1 on error
1184  */
1186  DetectPort **head, const char *str)
1187 {
1188  SCLogDebug("Port string to be parsed - str %s", str);
1189 
1190  /* negate port list */
1191  DetectPort *nhead = NULL;
1192 
1193  int r = DetectPortParseDo(de_ctx, head, &nhead, str,
1194  /* start with negate no */ 0, NULL, 0);
1195  if (r < 0)
1196  goto error;
1197 
1198  SCLogDebug("head %p %p, nhead %p", head, *head, nhead);
1199 
1200  /* merge the 'not' port groups */
1201  if (DetectPortParseMergeNotPorts(de_ctx, head, &nhead) < 0)
1202  goto error;
1203 
1204  /* free the temp negate head */
1205  DetectPortCleanupList(de_ctx, nhead);
1206  return 0;
1207 
1208 error:
1209  DetectPortCleanupList(de_ctx, nhead);
1210  return -1;
1211 }
1212 
1213 /**
1214  * \brief Helper function for parsing port strings
1215  *
1216  * \param str Pointer to the port string
1217  *
1218  * \retval DetectPort pointer of the parse string on success
1219  * \retval NULL on error
1220  */
1221 DetectPort *PortParse(const char *str)
1222 {
1223  char *port2 = NULL;
1224  char portstr[16];
1225 
1226  /* strip leading spaces */
1227  while (isspace(*str))
1228  str++;
1229  if (strlen(str) >= 16)
1230  return NULL;
1231  strlcpy(portstr, str, sizeof(portstr));
1232 
1233  DetectPort *dp = DetectPortInit();
1234  if (dp == NULL)
1235  goto error;
1236 
1237  /* we dup so we can put a nul-termination in it later */
1238  char *port = portstr;
1239 
1240  /* handle the negation case */
1241  if (port[0] == '!') {
1242  dp->flags |= PORT_FLAG_NOT;
1243  port++;
1244  }
1245 
1246  if ((port2 = strchr(port, ':')) != NULL) {
1247  /* 80:81 range format */
1248  port2[0] = '\0';
1249  port2++;
1250 
1251  if (strcmp(port, "") != 0) {
1252  if (!DetectPortIsValidRange(port, &dp->port))
1253  goto error;
1254  } else {
1255  dp->port = 0;
1256  }
1257 
1258  if (strcmp(port2, "") != 0) {
1259  if (!DetectPortIsValidRange(port2, &dp->port2))
1260  goto error;
1261  } else {
1262  dp->port2 = 65535;
1263  }
1264 
1265  /* a > b is illegal, a == b is ok */
1266  if (dp->port > dp->port2)
1267  goto error;
1268  } else {
1269  if (strcasecmp(port,"any") == 0) {
1270  dp->port = 0;
1271  dp->port2 = 65535;
1272  } else {
1273  if (!DetectPortIsValidRange(port, &dp->port))
1274  goto error;
1275  dp->port2 = dp->port;
1276  }
1277  }
1278 
1279  return dp;
1280 
1281 error:
1282  if (dp != NULL)
1283  DetectPortCleanupList(NULL, dp);
1284  return NULL;
1285 }
1286 
1287 /**
1288  * \brief Helper function to check if a parsed port is in the valid range
1289  * of available ports
1290  *
1291  * \param str Pointer to the port string
1292  *
1293  *
1294  * \retval true if port is in the valid range
1295  * \retval false if invalid
1296  */
1297 static bool DetectPortIsValidRange(char *port, uint16_t *port_val)
1298 {
1299  if (StringParseUint16(port_val, 10, 0, (const char *)port) < 0)
1300  return false;
1301 
1302  return true;
1303 }
1304 
1305 /********************** End parsing routines ********************/
1306 
1307 /* hash table */
1308 
1309 /**
1310  * \brief The hash function to be the used by the hash table -
1311  * DetectEngineCtx->dport_hash_table.
1312  *
1313  * \param ht Pointer to the hash table.
1314  * \param data Pointer to the DetectPort.
1315  * \param datalen Not used in our case.
1316  *
1317  * \retval hash The generated hash value.
1318  */
1319 static uint32_t DetectPortHashFunc(HashListTable *ht, void *data, uint16_t datalen)
1320 {
1321  DetectPort *p = (DetectPort *)data;
1322  SCLogDebug("hashing port %p", p);
1323 
1324  uint32_t hash = ((uint32_t)p->port << 16) | p->port2;
1325 
1326  hash %= ht->array_size;
1327  SCLogDebug("hash %"PRIu32, hash);
1328  return hash;
1329 }
1330 
1331 /**
1332  * \brief The Compare function to be used by the DetectPort hash table -
1333  * DetectEngineCtx->dport_hash_table.
1334  *
1335  * \param data1 Pointer to the first DetectPort.
1336  * \param len1 Not used.
1337  * \param data2 Pointer to the second DetectPort.
1338  * \param len2 Not used.
1339  *
1340  * \retval 1 If the 2 DetectPort sent as args match.
1341  * \retval 0 If the 2 DetectPort sent as args do not match.
1342  */
1343 static char DetectPortCompareFunc(void *data1, uint16_t len1,
1344  void *data2, uint16_t len2)
1345 {
1346  DetectPort *dp1 = (DetectPort *)data1;
1347  DetectPort *dp2 = (DetectPort *)data2;
1348 
1349  if (data1 == NULL || data2 == NULL)
1350  return 0;
1351 
1352  if (dp1->port == dp2->port && dp1->port2 == dp2->port2)
1353  return 1;
1354 
1355  return 0;
1356 }
1357 
1358 static void DetectPortHashFreeFunc(void *ptr)
1359 {
1360  DetectPort *p = ptr;
1361  DetectPortFree(NULL, p);
1362 }
1363 
1364 /**
1365  * \brief Initializes the hash table in the detection engine context to hold the
1366  * DetectPort hash.
1367  *
1368  * \param de_ctx Pointer to the detection engine context.
1369  *
1370  * \retval 0 On success.
1371  * \retval -1 On failure.
1372  */
1374 {
1375  de_ctx->dport_hash_table = HashListTableInit(4096, DetectPortHashFunc,
1376  DetectPortCompareFunc,
1377  DetectPortHashFreeFunc);
1378  if (de_ctx->dport_hash_table == NULL)
1379  return -1;
1380 
1381  return 0;
1382 }
1383 
1384 /**
1385  * \brief Adds a DetectPort to the detection engine context DetectPort
1386  * hash table.
1387  *
1388  * \param de_ctx Pointer to the detection engine context.
1389  * \param dp Pointer to the DetectPort.
1390  *
1391  * \retval ret 0 on Successfully adding the DetectPort; -1 on failure.
1392  */
1394 {
1395  int ret = HashListTableAdd(de_ctx->dport_hash_table, (void *)dp, 0);
1396  return ret;
1397 }
1398 
1399 /**
1400  * \brief Used to lookup a DetectPort hash from the detection engine context
1401  * DetectPort hash table.
1402  *
1403  * \param de_ctx Pointer to the detection engine context.
1404  * \param sgh Pointer to the DetectPort.
1405  *
1406  * \retval rsgh On success a pointer to the DetectPort if the DetectPort is
1407  * found in the hash table; NULL on failure.
1408  */
1410 {
1411  SCEnter();
1412 
1413  DetectPort *rdp = HashListTableLookup(de_ctx->dport_hash_table, (void *)dp, 0);
1414 
1415  SCReturnPtr(rdp, "DetectPort");
1416 }
1417 
1418 /**
1419  * \brief Frees the hash table - DetectEngineCtx->sgh_hash_table, allocated by
1420  * DetectPortInit() function.
1421  *
1422  * \param de_ctx Pointer to the detection engine context.
1423  */
1425 {
1426  if (de_ctx->sgh_hash_table == NULL)
1427  return;
1428 
1430  de_ctx->dport_hash_table = NULL;
1431 }
1432 
1433 /*---------------------- Unittests -------------------------*/
1434 
1435 #ifdef UNITTESTS
1436 #include "packet.h"
1437 
1438 /**
1439  * \test Check if a DetectPort is properly allocated
1440  */
1441 static int PortTestParse01 (void)
1442 {
1443  DetectPort *dd = NULL;
1444  int r = DetectPortParse(NULL,&dd,"80");
1445  FAIL_IF_NOT(r == 0);
1446  DetectPortFree(NULL, dd);
1447  PASS;
1448 }
1449 
1450 /**
1451  * \test Check if two ports are properly allocated in the DetectPort group
1452  */
1453 static int PortTestParse02 (void)
1454 {
1455  DetectPort *dd = NULL;
1456  int r = DetectPortParse(NULL,&dd,"80");
1457  FAIL_IF_NOT(r == 0);
1458  r = DetectPortParse(NULL,&dd,"22");
1459  FAIL_IF_NOT(r == 0);
1460  DetectPortCleanupList(NULL, dd);
1461  PASS;
1462 }
1463 
1464 /**
1465  * \test Check if two port ranges are properly allocated in the DetectPort group
1466  */
1467 static int PortTestParse03 (void)
1468 {
1469  DetectPort *dd = NULL;
1470  int r = DetectPortParse(NULL,&dd,"80:88");
1471  FAIL_IF_NOT(r == 0);
1472  r = DetectPortParse(NULL,&dd,"85:100");
1473  FAIL_IF_NOT(r == 0);
1474  DetectPortCleanupList(NULL, dd);
1475  PASS;
1476 }
1477 
1478 /**
1479  * \test Check if a negated port range is properly allocated in the DetectPort
1480  */
1481 static int PortTestParse04 (void)
1482 {
1483  DetectPort *dd = NULL;
1484  int r = DetectPortParse(NULL,&dd,"!80:81");
1485  FAIL_IF_NOT(r == 0);
1486  DetectPortCleanupList(NULL, dd);
1487  PASS;
1488 }
1489 
1490 /**
1491  * \test Check if a negated port range is properly fragmented in the allowed
1492  * real groups, ex !80:81 should allow 0:79 and 82:65535
1493  */
1494 static int PortTestParse05 (void)
1495 {
1496  DetectPort *dd = NULL;
1497  int r = DetectPortParse(NULL,&dd,"!80:81");
1498  FAIL_IF_NOT(r == 0);
1499  FAIL_IF_NULL(dd->next);
1500  FAIL_IF_NOT(dd->port == 0);
1501  FAIL_IF_NOT(dd->port2 == 79);
1502  FAIL_IF_NOT(dd->next->port == 82);
1503  FAIL_IF_NOT(dd->next->port2 == 65535);
1504  DetectPortCleanupList(NULL, dd);
1505  PASS;
1506 }
1507 
1508 /**
1509  * \test Check if a negated port range is properly fragmented in the allowed
1510  * real groups
1511  */
1512 static int PortTestParse07 (void)
1513 {
1514  DetectPort *dd = NULL;
1515 
1516  int r = DetectPortParse(NULL,&dd,"!21:902");
1517  FAIL_IF_NOT(r == 0);
1518  FAIL_IF_NULL(dd->next);
1519 
1520  FAIL_IF_NOT(dd->port == 0);
1521  FAIL_IF_NOT(dd->port2 == 20);
1522  FAIL_IF_NOT(dd->next->port == 903);
1523  FAIL_IF_NOT(dd->next->port2 == 65535);
1524 
1525  DetectPortCleanupList(NULL, dd);
1526  PASS;
1527 }
1528 
1529 /**
1530  * \test Check if we dont allow invalid port range specification
1531  */
1532 static int PortTestParse08 (void)
1533 {
1534  DetectPort *dd = NULL;
1535 
1536  int r = DetectPortParse(NULL,&dd,"[80:!80]");
1537  FAIL_IF(r == 0);
1538 
1539  DetectPortCleanupList(NULL, dd);
1540  PASS;
1541 }
1542 
1543 /**
1544  * \test Check if we autocomplete correctly an open range
1545  */
1546 static int PortTestParse09 (void)
1547 {
1548  DetectPort *dd = NULL;
1549 
1550  int r = DetectPortParse(NULL,&dd,"1024:");
1551  FAIL_IF_NOT(r == 0);
1552  FAIL_IF_NULL(dd);
1553 
1554  FAIL_IF_NOT(dd->port == 1024);
1555  FAIL_IF_NOT(dd->port2 == 0xffff);
1556 
1557  DetectPortCleanupList(NULL, dd);
1558  PASS;
1559 }
1560 
1561 /**
1562  * \test Test we don't allow a port that is too big
1563  */
1564 static int PortTestParse10 (void)
1565 {
1566  DetectPort *dd = NULL;
1567  int r = DetectPortParse(NULL,&dd,"77777777777777777777777777777777777777777777");
1568  FAIL_IF(r == 0);
1569  PASS;
1570 }
1571 
1572 /**
1573  * \test Test second port of range being too big
1574  */
1575 static int PortTestParse11 (void)
1576 {
1577  DetectPort *dd = NULL;
1578 
1579  int r = DetectPortParse(NULL,&dd,"1024:65536");
1580  FAIL_IF(r == 0);
1581  PASS;
1582 }
1583 
1584 /**
1585  * \test Test second port of range being just right
1586  */
1587 static int PortTestParse12 (void)
1588 {
1589  DetectPort *dd = NULL;
1590  int r = DetectPortParse(NULL,&dd,"1024:65535");
1591  FAIL_IF_NOT(r == 0);
1592  DetectPortFree(NULL, dd);
1593  PASS;
1594 }
1595 
1596 /**
1597  * \test Test first port of range being too big
1598  */
1599 static int PortTestParse13 (void)
1600 {
1601  DetectPort *dd = NULL;
1602  int r = DetectPortParse(NULL,&dd,"65536:65535");
1603  FAIL_IF(r == 0);
1604  PASS;
1605 }
1606 
1607 /**
1608  * \test Test merging port groups
1609  */
1610 static int PortTestParse14 (void)
1611 {
1612  DetectPort *dd = NULL;
1613 
1614  int r = DetectPortParseInsertString(NULL, &dd, "0:100");
1615  FAIL_IF_NOT(r == 0);
1616  r = DetectPortParseInsertString(NULL, &dd, "1000:65535");
1617  FAIL_IF_NOT(r == 0);
1618  FAIL_IF_NULL(dd->next);
1619 
1620  FAIL_IF_NOT(dd->port == 0);
1621  FAIL_IF_NOT(dd->port2 == 100);
1622  FAIL_IF_NOT(dd->next->port == 1000);
1623  FAIL_IF_NOT(dd->next->port2 == 65535);
1624 
1625  DetectPortCleanupList(NULL, dd);
1626  PASS;
1627 }
1628 
1629 /**
1630  * \test Test merging negated port groups
1631  */
1632 static int PortTestParse15 (void)
1633 {
1634  DetectPort *dd = NULL;
1635 
1636  int r = DetectPortParse(NULL,&dd,"![0:100,1000:3000]");
1637  FAIL_IF_NOT(r == 0);
1638  FAIL_IF_NULL(dd->next);
1639 
1640  FAIL_IF_NOT(dd->port == 101);
1641  FAIL_IF_NOT(dd->port2 == 999);
1642  FAIL_IF_NOT(dd->next->port == 3001);
1643  FAIL_IF_NOT(dd->next->port2 == 65535);
1644 
1645  DetectPortCleanupList(NULL, dd);
1646  PASS;
1647 }
1648 
1649 static int PortTestParse16 (void)
1650 {
1651  DetectPort *dd = NULL;
1652  int r = DetectPortParse(NULL,&dd,"\
1653 [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\
1654 1:65535\
1655 ]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\
1656 ");
1657  FAIL_IF_NOT(r == 0);
1658  DetectPortFree(NULL, dd);
1659  dd = NULL;
1660  r = DetectPortParse(NULL,&dd,"\
1661 [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\
1662 1:65535\
1663 ]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\
1664 ");
1665  FAIL_IF(r == 0);
1666  PASS;
1667 }
1668 
1669 /**
1670  * \test Test general functions
1671  */
1672 static int PortTestFunctions02(void)
1673 {
1674  DetectPort *head = NULL;
1675  DetectPort *dp1= NULL;
1676  DetectPort *dp2= NULL;
1677  int result = 0;
1678 
1679  /* Parse */
1680  int r = DetectPortParse(NULL,&head, "![0:100,1000:65535]");
1681  if (r != 0 || head->next != NULL)
1682  goto end;
1683 
1684  r = DetectPortParse(NULL, &dp1, "!200:300");
1685  if (r != 0 || dp1->next == NULL)
1686  goto end;
1687 
1688  /* Merge Nots */
1689  r = DetectPortParseMergeNotPorts(NULL, &head, &dp1);
1690  if (r != 0 || head->next != NULL)
1691  goto end;
1692 
1693  r = DetectPortParse(NULL, &dp2, "!100:500");
1694  if (r != 0 || dp2->next == NULL)
1695  goto end;
1696 
1697  /* Merge Nots */
1698  r = DetectPortParseMergeNotPorts(NULL, &head, &dp2);
1699  if (r != 0 || head->next != NULL)
1700  goto end;
1701 
1702  if (!(head->port == 200))
1703  goto end;
1704  if (!(head->port2 == 300))
1705  goto end;
1706 
1707  result = 1;
1708 
1709 end:
1710  if (dp1 != NULL)
1711  DetectPortCleanupList(NULL, dp1);
1712  if (dp2 != NULL)
1713  DetectPortCleanupList(NULL, dp2);
1714  if (head != NULL)
1715  DetectPortCleanupList(NULL, head);
1716  return result;
1717 }
1718 
1719 /**
1720  * \test Test general functions
1721  */
1722 static int PortTestFunctions03(void)
1723 {
1724  DetectPort *dp1= NULL;
1725  DetectPort *dp2= NULL;
1726  DetectPort *dp3= NULL;
1727  int result = 0;
1728 
1729  int r = DetectPortParse(NULL, &dp1, "200:300");
1730  if (r != 0)
1731  goto end;
1732 
1733  r = DetectPortParse(NULL, &dp2, "250:300");
1734  if (r != 0)
1735  goto end;
1736 
1737  /* Cut */
1738  DetectPortCut(NULL, dp1, dp2, &dp3);
1739  if (r != 0)
1740  goto end;
1741 
1742  if (!(dp1->port == 200))
1743  goto end;
1744  if (!(dp1->port2 == 249))
1745  goto end;
1746  if (!(dp2->port == 250))
1747  goto end;
1748  if (!(dp2->port2 == 300))
1749  goto end;
1750 
1751  dp1->port = 0;
1752  dp1->port2 = 500;
1753  dp2->port = 250;
1754  dp2->port2 = 750;
1755 
1756  /* Cut */
1757  DetectPortCut(NULL, dp1, dp2, &dp3);
1758  if (r != 0)
1759  goto end;
1760  if (!(dp1->port == 0))
1761  goto end;
1762  if (!(dp1->port2 == 249))
1763  goto end;
1764  if (!(dp2->port == 250))
1765  goto end;
1766  if (!(dp2->port2 == 500))
1767  goto end;
1768  if (!(dp3->port == 501))
1769  goto end;
1770  if (!(dp3->port2 == 750))
1771  goto end;
1772 
1773  result = 1;
1774 
1775 end:
1776  if (dp1 != NULL)
1777  DetectPortCleanupList(NULL, dp1);
1778  if (dp2 != NULL)
1779  DetectPortCleanupList(NULL, dp2);
1780  if (dp3 != NULL)
1781  DetectPortCleanupList(NULL, dp3);
1782  return result;
1783 }
1784 
1785 /**
1786  * \test Test general functions
1787  */
1788 static int PortTestFunctions04(void)
1789 {
1790  DetectPort *dp1 = NULL;
1791  DetectPort *dp2 = NULL;
1792  int result = 0;
1793 
1794  int r = DetectPortParse(NULL, &dp1, "200:300");
1795  if (r != 0)
1796  goto end;
1797 
1798  /* Cut Not */
1799  r = DetectPortCutNot(dp1, &dp2);
1800  if (r != 0)
1801  goto end;
1802 
1803  if (!(dp1->port == 0))
1804  goto end;
1805  if (!(dp1->port2 == 199))
1806  goto end;
1807  if (!(dp2->port == 301))
1808  goto end;
1809  if (!(dp2->port2 == 65535))
1810  goto end;
1811 
1812  result = 1;
1813 end:
1814  if (dp1 != NULL)
1815  DetectPortCleanupList(NULL, dp1);
1816  if (dp2 != NULL)
1817  DetectPortCleanupList(NULL, dp2);
1818  return result;
1819 }
1820 
1821 /**
1822  * \test Test general functions
1823  */
1824 static int PortTestFunctions07(void)
1825 {
1826  DetectPort *dd = NULL;
1827 
1828  // This one should fail due to negation in a range
1829  FAIL_IF(DetectPortParse(NULL, &dd, "[80:!99]") == 0);
1830 
1831  // Correct: from 80 till 100 but 99 excluded
1832  FAIL_IF_NOT(DetectPortParse(NULL, &dd, "[80:100,!99]") == 0);
1833  FAIL_IF_NULL(dd->next);
1834  FAIL_IF_NOT(dd->port == 80);
1835  FAIL_IF_NOT(dd->port2 == 98);
1836  FAIL_IF_NOT(dd->next->port == 100);
1837 
1838  // Also good: from 1 till 80 except of 2 and 4
1839  FAIL_IF_NOT(DetectPortParse(NULL, &dd, "[1:80,![2,4]]") == 0);
1840  FAIL_IF_NOT(dd->port == 1);
1844 
1845  DetectPortCleanupList(NULL, dd);
1846  PASS;
1847 }
1848 
1849 /**
1850  * \test Test packet Matches
1851  * \param raw_eth_pkt pointer to the ethernet packet
1852  * \param pktsize size of the packet
1853  * \param sig pointer to the signature to test
1854  * \param sid sid number of the signature
1855  * \retval return 1 if match
1856  * \retval return 0 if not
1857  */
1858 static int PortTestMatchReal(uint8_t *raw_eth_pkt, uint16_t pktsize, const char *sig,
1859  uint32_t sid)
1860 {
1861  int result = 0;
1863  Packet *p = UTHBuildPacketFromEth(raw_eth_pkt, pktsize);
1864  result = UTHPacketMatchSig(p, sig);
1865  PacketFree(p);
1866  FlowShutdown();
1867  return result;
1868 }
1869 
1870 /**
1871  * \brief Wrapper for PortTestMatchReal
1872  */
1873 static int PortTestMatchRealWrp(const char *sig, uint32_t sid)
1874 {
1875  /* Real HTTP packeth doing a GET method
1876  * tcp.sport=47370 tcp.dport=80
1877  * ip.src=192.168.28.131 ip.dst=192.168.1.1
1878  */
1879  uint8_t raw_eth_pkt[] = {
1880  0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
1881  0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
1882  0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
1883  0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
1884  0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
1885  0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
1886  0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
1887  0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
1888  0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
1889  0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
1890  0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
1891  0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
1892  0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
1893  0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
1894  0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
1895  0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
1896  0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
1897  0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
1898  0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
1899  0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
1900  0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
1901  0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
1902  0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
1903  0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
1904  0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
1905  0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
1906  0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
1907  0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
1908  0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
1909  0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
1910  0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
1911  0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
1912  0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
1913  0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
1914  0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
1915  0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
1916  0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
1917  0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
1918  0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
1919  0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
1920  0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
1921  0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
1922  0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
1923  0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
1924  0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
1925  0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
1926  0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
1927  0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
1928  0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
1929  0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
1930  0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
1931  0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
1932  0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
1933  0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
1934  0x76,0x65,0x0d,0x0a,0x0d,0x0a };
1935  /* end raw_eth_pkt */
1936 
1937  return PortTestMatchReal(raw_eth_pkt, (uint16_t)sizeof(raw_eth_pkt),
1938  sig, sid);
1939 }
1940 
1941 /**
1942  * \test Check if we match a dest port
1943  */
1944 static int PortTestMatchReal01(void)
1945 {
1946  /* tcp.sport=47370 tcp.dport=80 */
1947  const char *sig = "alert tcp any any -> any 80 (msg:\"Nothing..\"; content:\"GET\"; sid:1;)";
1948  return PortTestMatchRealWrp(sig, 1);
1949 }
1950 
1951 /**
1952  * \test Check if we match a source port
1953  */
1954 static int PortTestMatchReal02(void)
1955 {
1956  const char *sig = "alert tcp any 47370 -> any any (msg:\"Nothing..\";"
1957  " content:\"GET\"; sid:1;)";
1958  return PortTestMatchRealWrp(sig, 1);
1959 }
1960 
1961 /**
1962  * \test Check if we match both of them
1963  */
1964 static int PortTestMatchReal03(void)
1965 {
1966  const char *sig = "alert tcp any 47370 -> any 80 (msg:\"Nothing..\";"
1967  " content:\"GET\"; sid:1;)";
1968  return PortTestMatchRealWrp(sig, 1);
1969 }
1970 
1971 /**
1972  * \test Check if we negate dest ports correctly
1973  */
1974 static int PortTestMatchReal04(void)
1975 {
1976  const char *sig = "alert tcp any any -> any !80 (msg:\"Nothing..\";"
1977  " content:\"GET\"; sid:1;)";
1978  return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
1979 }
1980 
1981 /**
1982  * \test Check if we negate source ports correctly
1983  */
1984 static int PortTestMatchReal05(void)
1985 {
1986  const char *sig = "alert tcp any !47370 -> any any (msg:\"Nothing..\";"
1987  " content:\"GET\"; sid:1;)";
1988  return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
1989 }
1990 
1991 /**
1992  * \test Check if we negate both ports correctly
1993  */
1994 static int PortTestMatchReal06(void)
1995 {
1996  const char *sig = "alert tcp any !47370 -> any !80 (msg:\"Nothing..\";"
1997  " content:\"GET\"; sid:1;)";
1998  return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
1999 }
2000 
2001 /**
2002  * \test Check if we match a dest port range
2003  */
2004 static int PortTestMatchReal07(void)
2005 {
2006  const char *sig = "alert tcp any any -> any 70:100 (msg:\"Nothing..\";"
2007  " content:\"GET\"; sid:1;)";
2008  return PortTestMatchRealWrp(sig, 1);
2009 }
2010 
2011 /**
2012  * \test Check if we match a source port range
2013  */
2014 static int PortTestMatchReal08(void)
2015 {
2016  const char *sig = "alert tcp any 47000:50000 -> any any (msg:\"Nothing..\";"
2017  " content:\"GET\"; sid:1;)";
2018  return PortTestMatchRealWrp(sig, 1);
2019 }
2020 
2021 /**
2022  * \test Check if we match both port ranges
2023  */
2024 static int PortTestMatchReal09(void)
2025 {
2026  const char *sig = "alert tcp any 47000:50000 -> any 70:100 (msg:\"Nothing..\";"
2027  " content:\"GET\"; sid:1;)";
2028  return PortTestMatchRealWrp(sig, 1);
2029 }
2030 
2031 /**
2032  * \test Check if we negate a dest port range
2033  */
2034 static int PortTestMatchReal10(void)
2035 {
2036  const char *sig = "alert tcp any any -> any !70:100 (msg:\"Nothing..\";"
2037  " content:\"GET\"; sid:1;)";
2038  return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
2039 }
2040 
2041 /**
2042  * \test Check if we negate a source port range
2043  */
2044 static int PortTestMatchReal11(void)
2045 {
2046  const char *sig = "alert tcp any !47000:50000 -> any any (msg:\"Nothing..\";"
2047  " content:\"GET\"; sid:1;)";
2048  return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
2049 }
2050 
2051 /**
2052  * \test Check if we negate both port ranges
2053  */
2054 static int PortTestMatchReal12(void)
2055 {
2056  const char *sig = "alert tcp any !47000:50000 -> any !70:100 (msg:\"Nothing..\";"
2057  " content:\"GET\"; sid:1;)";
2058  return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
2059 }
2060 
2061 /**
2062  * \test Check if we autocomplete ranges correctly
2063  */
2064 static int PortTestMatchReal13(void)
2065 {
2066  const char *sig = "alert tcp any 47000:50000 -> any !81: (msg:\"Nothing..\";"
2067  " content:\"GET\"; sid:1;)";
2068  return PortTestMatchRealWrp(sig, 1);
2069 }
2070 
2071 /**
2072  * \test Check if we autocomplete ranges correctly
2073  */
2074 static int PortTestMatchReal14(void)
2075 {
2076  const char *sig = "alert tcp any !48000:50000 -> any :100 (msg:\"Nothing..\";"
2077  " content:\"GET\"; sid:1;)";
2078  return PortTestMatchRealWrp(sig, 1);
2079 }
2080 
2081 /**
2082  * \test Check if we autocomplete ranges correctly
2083  */
2084 static int PortTestMatchReal15(void)
2085 {
2086  const char *sig = "alert tcp any :50000 -> any 81:100 (msg:\"Nothing..\";"
2087  " content:\"GET\"; sid:1;)";
2088  return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
2089 }
2090 
2091 /**
2092  * \test Check if we separate ranges correctly
2093  */
2094 static int PortTestMatchReal16(void)
2095 {
2096  const char *sig = "alert tcp any 100: -> any ![0:79,81:65535] (msg:\"Nothing..\";"
2097  " content:\"GET\"; sid:1;)";
2098  return PortTestMatchRealWrp(sig, 1);
2099 }
2100 
2101 /**
2102  * \test Check if we separate ranges correctly
2103  */
2104 static int PortTestMatchReal17(void)
2105 {
2106  const char *sig = "alert tcp any ![0:39999,48000:50000] -> any ![0:80,82:65535] "
2107  "(msg:\"Nothing..\"; content:\"GET\"; sid:1;)";
2108  return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
2109 }
2110 
2111 /**
2112  * \test Check if we separate ranges correctly
2113  */
2114 static int PortTestMatchReal18(void)
2115 {
2116  const char *sig = "alert tcp any ![0:39999,48000:50000] -> any 80 (msg:\"Nothing"
2117  " at all\"; content:\"GET\"; sid:1;)";
2118  return PortTestMatchRealWrp(sig, 1);
2119 }
2120 
2121 /**
2122  * \test Check if we separate ranges correctly
2123  */
2124 static int PortTestMatchReal19(void)
2125 {
2126  const char *sig = "alert tcp any any -> any 80 (msg:\"Nothing..\";"
2127  " content:\"GET\"; sid:1;)";
2128  return PortTestMatchRealWrp(sig, 1);
2129 }
2130 
2131 static int PortTestMatchDoubleNegation(void)
2132 {
2133  DetectPort *head = NULL, *nhead = NULL;
2134  FAIL_IF(DetectPortParseDo(NULL, &head, &nhead, "![!80]", 0, NULL, 0) == -1);
2135  FAIL_IF_NOT(head != NULL);
2136  FAIL_IF_NOT(nhead == NULL);
2137  DetectPortCleanupList(NULL, head);
2138  PASS;
2139 }
2140 
2141 // Test that negation is successfully parsed with whitespace for port strings of
2142 // length < 16
2143 static int DetectPortParseDoTest(void)
2144 {
2147  DetectPort *head = NULL;
2148  DetectPort *nhead = NULL;
2149  const char *str = "[30:50, !45]";
2150  int r = DetectPortParseDo(de_ctx, &head, &nhead, str, 0, NULL, 0);
2151 
2152  // Assertions
2153  FAIL_IF_NULL(head);
2154  FAIL_IF_NULL(nhead);
2155  FAIL_IF(r < 0);
2156  FAIL_IF(head->port != 30);
2157  FAIL_IF(head->port2 != 50);
2158  FAIL_IF(nhead->port != 45);
2159  FAIL_IF(nhead->port2 != 45);
2160  DetectPortCleanupList(NULL, head);
2161  DetectPortCleanupList(NULL, nhead);
2163  PASS;
2164 }
2165 
2166 static int DetectPortParseDoTest2(void)
2167 {
2170  DetectPort *head = NULL;
2171  DetectPort *nhead = NULL;
2172  const char *str = "[30:50, !45]";
2173  int r = DetectPortParseDo(de_ctx, &head, &nhead, str, 0, NULL, 0);
2174  FAIL_IF(r < 0);
2175  DetectPortCleanupList(NULL, head);
2176  DetectPortCleanupList(NULL, nhead);
2178  PASS;
2179 }
2180 
2181 // Verifies correct parsing when negation port string length < 16
2182 static int PortParseTestLessThan14Spaces(void)
2183 {
2184  const char *str = " 45";
2185  DetectPort *dp = PortParse(str);
2186  FAIL_IF_NULL(dp);
2187  FAIL_IF(dp->port != 45);
2188  FAIL_IF(dp->port2 != 45);
2189  DetectPortFree(NULL, dp);
2190  PASS;
2191 }
2192 
2193 // Verifies NULL returned when negation port string length == 16
2194 static int PortParseTest14Spaces(void)
2195 {
2196  const char *str = " 45";
2197  DetectPort *dp = PortParse(str);
2198  FAIL_IF_NULL(dp);
2199  FAIL_IF(dp->port != 45);
2200  FAIL_IF(dp->port2 != 45);
2201  DetectPortFree(NULL, dp);
2202  PASS;
2203 }
2204 
2205 // Verifies NULL returned when negation port string length >= 16
2206 static int PortParseTestMoreThan14Spaces(void)
2207 {
2208  const char *str = " 45";
2209  DetectPort *dp = PortParse(str);
2210  FAIL_IF_NULL(dp);
2211  FAIL_IF(dp->port != 45);
2212  FAIL_IF(dp->port2 != 45);
2213  DetectPortFree(NULL, dp);
2214  PASS;
2215 }
2216 
2217 void DetectPortTests(void)
2218 {
2219  UtRegisterTest("PortTestParse01", PortTestParse01);
2220  UtRegisterTest("PortTestParse02", PortTestParse02);
2221  UtRegisterTest("PortTestParse03", PortTestParse03);
2222  UtRegisterTest("PortTestParse04", PortTestParse04);
2223  UtRegisterTest("PortTestParse05", PortTestParse05);
2224  UtRegisterTest("PortTestParse07", PortTestParse07);
2225  UtRegisterTest("PortTestParse08", PortTestParse08);
2226  UtRegisterTest("PortTestParse09", PortTestParse09);
2227  UtRegisterTest("PortTestParse10", PortTestParse10);
2228  UtRegisterTest("PortTestParse11", PortTestParse11);
2229  UtRegisterTest("PortTestParse12", PortTestParse12);
2230  UtRegisterTest("PortTestParse13", PortTestParse13);
2231  UtRegisterTest("PortTestParse14", PortTestParse14);
2232  UtRegisterTest("PortTestParse15", PortTestParse15);
2233  UtRegisterTest("PortTestParse16", PortTestParse16);
2234  UtRegisterTest("PortTestFunctions02", PortTestFunctions02);
2235  UtRegisterTest("PortTestFunctions03", PortTestFunctions03);
2236  UtRegisterTest("PortTestFunctions04", PortTestFunctions04);
2237  UtRegisterTest("PortTestFunctions07", PortTestFunctions07);
2238  UtRegisterTest("PortTestMatchReal01", PortTestMatchReal01);
2239  UtRegisterTest("PortTestMatchReal02", PortTestMatchReal02);
2240  UtRegisterTest("PortTestMatchReal03", PortTestMatchReal03);
2241  UtRegisterTest("PortTestMatchReal04", PortTestMatchReal04);
2242  UtRegisterTest("PortTestMatchReal05", PortTestMatchReal05);
2243  UtRegisterTest("PortTestMatchReal06", PortTestMatchReal06);
2244  UtRegisterTest("PortTestMatchReal07", PortTestMatchReal07);
2245  UtRegisterTest("PortTestMatchReal08", PortTestMatchReal08);
2246  UtRegisterTest("PortTestMatchReal09", PortTestMatchReal09);
2247  UtRegisterTest("PortTestMatchReal10", PortTestMatchReal10);
2248  UtRegisterTest("PortTestMatchReal11", PortTestMatchReal11);
2249  UtRegisterTest("PortTestMatchReal12", PortTestMatchReal12);
2250  UtRegisterTest("PortTestMatchReal13", PortTestMatchReal13);
2251  UtRegisterTest("PortTestMatchReal14", PortTestMatchReal14);
2252  UtRegisterTest("PortTestMatchReal15", PortTestMatchReal15);
2253  UtRegisterTest("PortTestMatchReal16", PortTestMatchReal16);
2254  UtRegisterTest("PortTestMatchReal17", PortTestMatchReal17);
2255  UtRegisterTest("PortTestMatchReal18", PortTestMatchReal18);
2256  UtRegisterTest("PortTestMatchReal19", PortTestMatchReal19);
2257  UtRegisterTest("PortTestMatchDoubleNegation", PortTestMatchDoubleNegation);
2258  UtRegisterTest("DetectPortParseDoTest", DetectPortParseDoTest);
2259  UtRegisterTest("DetectPortParseDoTest2", DetectPortParseDoTest2);
2260  UtRegisterTest("PortParseTestLessThan14Spaces", PortParseTestLessThan14Spaces);
2261  UtRegisterTest("PortParseTest14Spaces", PortParseTest14Spaces);
2262  UtRegisterTest("PortParseTestMoreThan14Spaces", PortParseTestMoreThan14Spaces);
2263 }
2264 
2265 #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:497
detect-engine.h
PORT_GT
@ PORT_GT
Definition: detect.h:212
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:1373
detect-engine-siggroup.h
DetectPortListsAreEqual
bool DetectPortListsAreEqual(DetectPort *list1, DetectPort *list2)
Checks if two port group lists are equal.
Definition: detect-engine-port.c:638
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
DetectPortFree
void DetectPortFree(const DetectEngineCtx *de_ctx, DetectPort *dp)
Free a DetectPort and its members.
Definition: detect-engine-port.c:80
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:279
PORT_ES
@ PORT_ES
Definition: detect.h:209
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
DetectPort_::port
uint16_t port
Definition: detect.h:221
PORT_SIGGROUPHEAD_COPY
#define PORT_SIGGROUPHEAD_COPY
Definition: detect.h:217
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:343
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:252
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2634
PORT_GE
@ PORT_GE
Definition: detect.h:211
DetectPort_::next
struct DetectPort_ * next
Definition: detect.h:234
UTHPacketMatchSig
int UTHPacketMatchSig(Packet *p, const char *sig)
Definition: util-unittest-helper.c:831
DetectEngineCtx_::dport_hash_table
HashListTable * dport_hash_table
Definition: detect.h:1066
DetectPort_::sh
struct SigGroupHead_ * sh
Definition: detect.h:231
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:1109
PORT_LE
@ PORT_LE
Definition: detect.h:207
util-var.h
PortParse
DetectPort * PortParse(const char *str)
Helper function for parsing port strings.
Definition: detect-engine-port.c:1221
DetectPort_::port2
uint16_t port2
Definition: detect.h:222
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:224
DetectPortPrint
void DetectPortPrint(DetectPort *dp)
Helper function that print the DetectPort info.
Definition: detect-engine-port.c:590
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:549
DetectPortCopySingle
DetectPort * DetectPortCopySingle(DetectEngineCtx *de_ctx, DetectPort *src)
Function that return a copy of DetectPort src sigs.
Definition: detect-engine-port.c:550
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:1185
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
PORT_FLAG_ANY
#define PORT_FLAG_ANY
Definition: detect.h:215
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:18
SCEnter
#define SCEnter(...)
Definition: util-debug.h:281
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_LT
@ PORT_LT
Definition: detect.h:206
DetectPort_
Port structure for detection engine.
Definition: detect.h:220
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
PORT_ER
@ PORT_ER
Definition: detect.h:205
SCReturnPtr
#define SCReturnPtr(x, type)
Definition: util-debug.h:297
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_EB
@ PORT_EB
Definition: detect.h:210
Flow_::next
struct Flow_ * next
Definition: flow.h:388
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
PORT_EQ
@ PORT_EQ
Definition: detect.h:208
suricata-common.h
HashListTableFree
void HashListTableFree(HashListTable *ht)
Definition: util-hashlist.c:88
FlowShutdown
void FlowShutdown(void)
shutdown the flow engine
Definition: flow.c:693
packet.h
DetectPort_::prev
struct DetectPort_ * prev
Definition: detect.h:233
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:181
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:271
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:2595
PORT_FLAG_NOT
#define PORT_FLAG_NOT
Definition: detect.h:216
DetectPortHashAdd
int DetectPortHashAdd(DetectEngineCtx *de_ctx, DetectPort *dp)
Adds a DetectPort to the detection engine context DetectPort hash table.
Definition: detect-engine-port.c:1393
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:1424
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:1409
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:767
DetectPortLookupGroup
DetectPort * DetectPortLookupGroup(DetectPort *dp, uint16_t port)
Function that find the group matching port in a group head.
Definition: detect-engine-port.c:613
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