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  * \brief Do a sorted insert, where the top of the list should be the biggest
1440  * port range.
1441  *
1442  * \todo XXX current sorting only works for overlapping ranges
1443  *
1444  * \param head Pointer to the DetectPort list head
1445  * \param dp Pointer to DetectPort to search in the DetectPort list
1446  * \retval 0 if dp is added correctly
1447  */
1448 static int PortTestDetectPortAdd(DetectPort **head, DetectPort *dp)
1449 {
1450  DetectPort *cur, *prev_cur = NULL;
1451 
1452  //SCLogDebug("DetectPortAdd: adding "); DetectPortPrint(ag); SCLogDebug("");
1453 
1454  if (*head != NULL) {
1455  for (cur = *head; cur != NULL; cur = cur->next) {
1456  prev_cur = cur;
1457  int r = DetectPortCmp(dp,cur);
1458  if (r == PORT_EB) {
1459  /* insert here */
1460  dp->prev = cur->prev;
1461  dp->next = cur;
1462 
1463  cur->prev = dp;
1464  if (*head == cur) {
1465  *head = dp;
1466  } else {
1467  dp->prev->next = dp;
1468  }
1469  return 0;
1470  }
1471  }
1472  dp->prev = prev_cur;
1473  if (prev_cur != NULL)
1474  prev_cur->next = dp;
1475  } else {
1476  *head = dp;
1477  }
1478 
1479  return 0;
1480 }
1481 
1482 
1483 /**
1484  * \test Check if a DetectPort is properly allocated
1485  */
1486 static int PortTestParse01 (void)
1487 {
1488  DetectPort *dd = NULL;
1489  int r = DetectPortParse(NULL,&dd,"80");
1490  FAIL_IF_NOT(r == 0);
1491  DetectPortFree(NULL, dd);
1492  PASS;
1493 }
1494 
1495 /**
1496  * \test Check if two ports are properly allocated in the DetectPort group
1497  */
1498 static int PortTestParse02 (void)
1499 {
1500  DetectPort *dd = NULL;
1501  int r = DetectPortParse(NULL,&dd,"80");
1502  FAIL_IF_NOT(r == 0);
1503  r = DetectPortParse(NULL,&dd,"22");
1504  FAIL_IF_NOT(r == 0);
1505  DetectPortCleanupList(NULL, dd);
1506  PASS;
1507 }
1508 
1509 /**
1510  * \test Check if two port ranges are properly allocated in the DetectPort group
1511  */
1512 static int PortTestParse03 (void)
1513 {
1514  DetectPort *dd = NULL;
1515  int r = DetectPortParse(NULL,&dd,"80:88");
1516  FAIL_IF_NOT(r == 0);
1517  r = DetectPortParse(NULL,&dd,"85:100");
1518  FAIL_IF_NOT(r == 0);
1519  DetectPortCleanupList(NULL, dd);
1520  PASS;
1521 }
1522 
1523 /**
1524  * \test Check if a negated port range is properly allocated in the DetectPort
1525  */
1526 static int PortTestParse04 (void)
1527 {
1528  DetectPort *dd = NULL;
1529  int r = DetectPortParse(NULL,&dd,"!80:81");
1530  FAIL_IF_NOT(r == 0);
1531  DetectPortCleanupList(NULL, dd);
1532  PASS;
1533 }
1534 
1535 /**
1536  * \test Check if a negated port range is properly fragmented in the allowed
1537  * real groups, ex !80:81 should allow 0:79 and 82:65535
1538  */
1539 static int PortTestParse05 (void)
1540 {
1541  DetectPort *dd = NULL;
1542  int r = DetectPortParse(NULL,&dd,"!80:81");
1543  FAIL_IF_NOT(r == 0);
1544  FAIL_IF_NULL(dd->next);
1545  FAIL_IF_NOT(dd->port == 0);
1546  FAIL_IF_NOT(dd->port2 == 79);
1547  FAIL_IF_NOT(dd->next->port == 82);
1548  FAIL_IF_NOT(dd->next->port2 == 65535);
1549  DetectPortCleanupList(NULL, dd);
1550  PASS;
1551 }
1552 
1553 /**
1554  * \test Check if a negated port range is properly fragmented in the allowed
1555  * real groups
1556  */
1557 static int PortTestParse07 (void)
1558 {
1559  DetectPort *dd = NULL;
1560 
1561  int r = DetectPortParse(NULL,&dd,"!21:902");
1562  FAIL_IF_NOT(r == 0);
1563  FAIL_IF_NULL(dd->next);
1564 
1565  FAIL_IF_NOT(dd->port == 0);
1566  FAIL_IF_NOT(dd->port2 == 20);
1567  FAIL_IF_NOT(dd->next->port == 903);
1568  FAIL_IF_NOT(dd->next->port2 == 65535);
1569 
1570  DetectPortCleanupList(NULL, dd);
1571  PASS;
1572 }
1573 
1574 /**
1575  * \test Check if we dont allow invalid port range specification
1576  */
1577 static int PortTestParse08 (void)
1578 {
1579  DetectPort *dd = NULL;
1580 
1581  int r = DetectPortParse(NULL,&dd,"[80:!80]");
1582  FAIL_IF(r == 0);
1583 
1584  DetectPortCleanupList(NULL, dd);
1585  PASS;
1586 }
1587 
1588 /**
1589  * \test Check if we autocomplete correctly an open range
1590  */
1591 static int PortTestParse09 (void)
1592 {
1593  DetectPort *dd = NULL;
1594 
1595  int r = DetectPortParse(NULL,&dd,"1024:");
1596  FAIL_IF_NOT(r == 0);
1597  FAIL_IF_NULL(dd);
1598 
1599  FAIL_IF_NOT(dd->port == 1024);
1600  FAIL_IF_NOT(dd->port2 == 0xffff);
1601 
1602  DetectPortCleanupList(NULL, dd);
1603  PASS;
1604 }
1605 
1606 /**
1607  * \test Test we don't allow a port that is too big
1608  */
1609 static int PortTestParse10 (void)
1610 {
1611  DetectPort *dd = NULL;
1612  int r = DetectPortParse(NULL,&dd,"77777777777777777777777777777777777777777777");
1613  FAIL_IF(r == 0);
1614  PASS;
1615 }
1616 
1617 /**
1618  * \test Test second port of range being too big
1619  */
1620 static int PortTestParse11 (void)
1621 {
1622  DetectPort *dd = NULL;
1623 
1624  int r = DetectPortParse(NULL,&dd,"1024:65536");
1625  FAIL_IF(r == 0);
1626  PASS;
1627 }
1628 
1629 /**
1630  * \test Test second port of range being just right
1631  */
1632 static int PortTestParse12 (void)
1633 {
1634  DetectPort *dd = NULL;
1635  int r = DetectPortParse(NULL,&dd,"1024:65535");
1636  FAIL_IF_NOT(r == 0);
1637  DetectPortFree(NULL, dd);
1638  PASS;
1639 }
1640 
1641 /**
1642  * \test Test first port of range being too big
1643  */
1644 static int PortTestParse13 (void)
1645 {
1646  DetectPort *dd = NULL;
1647  int r = DetectPortParse(NULL,&dd,"65536:65535");
1648  FAIL_IF(r == 0);
1649  PASS;
1650 }
1651 
1652 /**
1653  * \test Test merging port groups
1654  */
1655 static int PortTestParse14 (void)
1656 {
1657  DetectPort *dd = NULL;
1658 
1659  int r = DetectPortParseInsertString(NULL, &dd, "0:100");
1660  FAIL_IF_NOT(r == 0);
1661  r = DetectPortParseInsertString(NULL, &dd, "1000:65535");
1662  FAIL_IF_NOT(r == 0);
1663  FAIL_IF_NULL(dd->next);
1664 
1665  FAIL_IF_NOT(dd->port == 0);
1666  FAIL_IF_NOT(dd->port2 == 100);
1667  FAIL_IF_NOT(dd->next->port == 1000);
1668  FAIL_IF_NOT(dd->next->port2 == 65535);
1669 
1670  DetectPortCleanupList(NULL, dd);
1671  PASS;
1672 }
1673 
1674 /**
1675  * \test Test merging negated port groups
1676  */
1677 static int PortTestParse15 (void)
1678 {
1679  DetectPort *dd = NULL;
1680 
1681  int r = DetectPortParse(NULL,&dd,"![0:100,1000:3000]");
1682  FAIL_IF_NOT(r == 0);
1683  FAIL_IF_NULL(dd->next);
1684 
1685  FAIL_IF_NOT(dd->port == 101);
1686  FAIL_IF_NOT(dd->port2 == 999);
1687  FAIL_IF_NOT(dd->next->port == 3001);
1688  FAIL_IF_NOT(dd->next->port2 == 65535);
1689 
1690  DetectPortCleanupList(NULL, dd);
1691  PASS;
1692 }
1693 
1694 static int PortTestParse16 (void)
1695 {
1696  DetectPort *dd = NULL;
1697  int r = DetectPortParse(NULL,&dd,"\
1698 [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\
1699 1:65535\
1700 ]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\
1701 ");
1702  FAIL_IF_NOT(r == 0);
1703  DetectPortFree(NULL, dd);
1704  dd = NULL;
1705  r = DetectPortParse(NULL,&dd,"\
1706 [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\
1707 1:65535\
1708 ]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\
1709 ");
1710  FAIL_IF(r == 0);
1711  PASS;
1712 }
1713 
1714 /**
1715  * \test Test general functions
1716  */
1717 static int PortTestFunctions01(void)
1718 {
1719  DetectPort *head = NULL;
1720  DetectPort *dp1= NULL;
1721  int result = 0;
1722 
1723  /* Parse */
1724  int r = DetectPortParse(NULL,&head,"![0:100,1000:65535]");
1725  if (r != 0 || head->next != NULL)
1726  goto end;
1727 
1728  /* We should have only one DetectPort */
1729  if (!(head->port == 101))
1730  goto end;
1731  if (!(head->port2 == 999))
1732  goto end;
1733  if (!(head->next == NULL))
1734  goto end;
1735 
1736  r = DetectPortParse(NULL, &dp1,"2000:3000");
1737  if (r != 0 || dp1->next != NULL)
1738  goto end;
1739  if (!(dp1->port == 2000))
1740  goto end;
1741  if (!(dp1->port2 == 3000))
1742  goto end;
1743 
1744  /* Add */
1745  r = PortTestDetectPortAdd(&head, dp1);
1746  if (r != 0 || head->next == NULL)
1747  goto end;
1748  if (!(head->port == 101))
1749  goto end;
1750  if (!(head->port2 == 999))
1751  goto end;
1752  if (!(head->next->port == 2000))
1753  goto end;
1754  if (!(head->next->port2 == 3000))
1755  goto end;
1756 
1757  /* Match */
1758  if (!DetectPortMatch(head, 150))
1759  goto end;
1760  if (DetectPortMatch(head->next, 1500))
1761  goto end;
1762  if ((DetectPortMatch(head, 3500)))
1763  goto end;
1764  if ((DetectPortMatch(head, 50)))
1765  goto end;
1766 
1767  result = 1;
1768 end:
1769  if (dp1 != NULL)
1770  DetectPortFree(NULL, dp1);
1771  if (head != NULL)
1772  DetectPortFree(NULL, head);
1773  return result;
1774 }
1775 
1776 /**
1777  * \test Test general functions
1778  */
1779 static int PortTestFunctions02(void)
1780 {
1781  DetectPort *head = NULL;
1782  DetectPort *dp1= NULL;
1783  DetectPort *dp2= NULL;
1784  int result = 0;
1785 
1786  /* Parse */
1787  int r = DetectPortParse(NULL,&head, "![0:100,1000:65535]");
1788  if (r != 0 || head->next != NULL)
1789  goto end;
1790 
1791  r = DetectPortParse(NULL, &dp1, "!200:300");
1792  if (r != 0 || dp1->next == NULL)
1793  goto end;
1794 
1795  /* Merge Nots */
1796  r = DetectPortParseMergeNotPorts(NULL, &head, &dp1);
1797  if (r != 0 || head->next != NULL)
1798  goto end;
1799 
1800  r = DetectPortParse(NULL, &dp2, "!100:500");
1801  if (r != 0 || dp2->next == NULL)
1802  goto end;
1803 
1804  /* Merge Nots */
1805  r = DetectPortParseMergeNotPorts(NULL, &head, &dp2);
1806  if (r != 0 || head->next != NULL)
1807  goto end;
1808 
1809  if (!(head->port == 200))
1810  goto end;
1811  if (!(head->port2 == 300))
1812  goto end;
1813 
1814  result = 1;
1815 
1816 end:
1817  if (dp1 != NULL)
1818  DetectPortFree(NULL, dp1);
1819  if (dp2 != NULL)
1820  DetectPortFree(NULL, dp2);
1821  if (head != NULL)
1822  DetectPortFree(NULL, head);
1823  return result;
1824 }
1825 
1826 /**
1827  * \test Test general functions
1828  */
1829 static int PortTestFunctions03(void)
1830 {
1831  DetectPort *dp1= NULL;
1832  DetectPort *dp2= NULL;
1833  DetectPort *dp3= NULL;
1834  int result = 0;
1835 
1836  int r = DetectPortParse(NULL, &dp1, "200:300");
1837  if (r != 0)
1838  goto end;
1839 
1840  r = DetectPortParse(NULL, &dp2, "250:300");
1841  if (r != 0)
1842  goto end;
1843 
1844  /* Cut */
1845  DetectPortCut(NULL, dp1, dp2, &dp3);
1846  if (r != 0)
1847  goto end;
1848 
1849  if (!(dp1->port == 200))
1850  goto end;
1851  if (!(dp1->port2 == 249))
1852  goto end;
1853  if (!(dp2->port == 250))
1854  goto end;
1855  if (!(dp2->port2 == 300))
1856  goto end;
1857 
1858  dp1->port = 0;
1859  dp1->port2 = 500;
1860  dp2->port = 250;
1861  dp2->port2 = 750;
1862 
1863  /* Cut */
1864  DetectPortCut(NULL, dp1, dp2, &dp3);
1865  if (r != 0)
1866  goto end;
1867  if (!(dp1->port == 0))
1868  goto end;
1869  if (!(dp1->port2 == 249))
1870  goto end;
1871  if (!(dp2->port == 250))
1872  goto end;
1873  if (!(dp2->port2 == 500))
1874  goto end;
1875  if (!(dp3->port == 501))
1876  goto end;
1877  if (!(dp3->port2 == 750))
1878  goto end;
1879 
1880  result = 1;
1881 
1882 end:
1883  if (dp1 != NULL)
1884  DetectPortFree(NULL, dp1);
1885  if (dp2 != NULL)
1886  DetectPortFree(NULL, dp2);
1887  if (dp3 != NULL)
1888  DetectPortFree(NULL, dp3);
1889  return result;
1890 }
1891 
1892 /**
1893  * \test Test general functions
1894  */
1895 static int PortTestFunctions04(void)
1896 {
1897  DetectPort *dp1= NULL;
1898  DetectPort *dp2= NULL;
1899  int result = 0;
1900 
1901  int r = DetectPortParse(NULL, &dp1, "200:300");
1902  if (r != 0)
1903  goto end;
1904 
1905  dp2 = DetectPortInit();
1906 
1907  /* Cut Not */
1908  DetectPortCutNot(dp1, &dp2);
1909  if (r != 0)
1910  goto end;
1911 
1912  if (!(dp1->port == 0))
1913  goto end;
1914  if (!(dp1->port2 == 199))
1915  goto end;
1916  if (!(dp2->port == 301))
1917  goto end;
1918  if (!(dp2->port2 == 65535))
1919  goto end;
1920 
1921  result = 1;
1922 end:
1923  if (dp1 != NULL)
1924  DetectPortFree(NULL, dp1);
1925  if (dp2 != NULL)
1926  DetectPortFree(NULL, dp2);
1927  return result;
1928 }
1929 
1930 /**
1931  * \test Test general functions
1932  */
1933 static int PortTestFunctions07(void)
1934 {
1935  DetectPort *dd = NULL;
1936 
1937  // This one should fail due to negation in a range
1938  FAIL_IF(DetectPortParse(NULL, &dd, "[80:!99]") == 0);
1939 
1940  // Correct: from 80 till 100 but 99 excluded
1941  FAIL_IF_NOT(DetectPortParse(NULL, &dd, "[80:100,!99]") == 0);
1942  FAIL_IF_NULL(dd->next);
1943  FAIL_IF_NOT(dd->port == 80);
1944  FAIL_IF_NOT(dd->port2 == 98);
1945  FAIL_IF_NOT(dd->next->port == 100);
1946 
1947  // Also good: from 1 till 80 except of 2 and 4
1948  FAIL_IF_NOT(DetectPortParse(NULL, &dd, "[1:80,![2,4]]") == 0);
1949  FAIL_IF_NOT(dd->port == 1);
1953 
1954  DetectPortCleanupList(NULL, dd);
1955  PASS;
1956 }
1957 
1958 /**
1959  * \test Test packet Matches
1960  * \param raw_eth_pkt pointer to the ethernet packet
1961  * \param pktsize size of the packet
1962  * \param sig pointer to the signature to test
1963  * \param sid sid number of the signature
1964  * \retval return 1 if match
1965  * \retval return 0 if not
1966  */
1967 static int PortTestMatchReal(uint8_t *raw_eth_pkt, uint16_t pktsize, const char *sig,
1968  uint32_t sid)
1969 {
1970  int result = 0;
1972  Packet *p = UTHBuildPacketFromEth(raw_eth_pkt, pktsize);
1973  result = UTHPacketMatchSig(p, sig);
1974  PacketRecycle(p);
1975  FlowShutdown();
1976  return result;
1977 }
1978 
1979 /**
1980  * \brief Wrapper for PortTestMatchReal
1981  */
1982 static int PortTestMatchRealWrp(const char *sig, uint32_t sid)
1983 {
1984  /* Real HTTP packeth doing a GET method
1985  * tcp.sport=47370 tcp.dport=80
1986  * ip.src=192.168.28.131 ip.dst=192.168.1.1
1987  */
1988  uint8_t raw_eth_pkt[] = {
1989  0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
1990  0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
1991  0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
1992  0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
1993  0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
1994  0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
1995  0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
1996  0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
1997  0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
1998  0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
1999  0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
2000  0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
2001  0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
2002  0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
2003  0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
2004  0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
2005  0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
2006  0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
2007  0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
2008  0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
2009  0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
2010  0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
2011  0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
2012  0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
2013  0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
2014  0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
2015  0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
2016  0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
2017  0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
2018  0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
2019  0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
2020  0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
2021  0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
2022  0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
2023  0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
2024  0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
2025  0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
2026  0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
2027  0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
2028  0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
2029  0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
2030  0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
2031  0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
2032  0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
2033  0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
2034  0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
2035  0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
2036  0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
2037  0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
2038  0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
2039  0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
2040  0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
2041  0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
2042  0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
2043  0x76,0x65,0x0d,0x0a,0x0d,0x0a };
2044  /* end raw_eth_pkt */
2045 
2046  return PortTestMatchReal(raw_eth_pkt, (uint16_t)sizeof(raw_eth_pkt),
2047  sig, sid);
2048 }
2049 
2050 /**
2051  * \test Check if we match a dest port
2052  */
2053 static int PortTestMatchReal01(void)
2054 {
2055  /* tcp.sport=47370 tcp.dport=80 */
2056  const char *sig = "alert tcp any any -> any 80 (msg:\"Nothing..\"; content:\"GET\"; sid:1;)";
2057  return PortTestMatchRealWrp(sig, 1);
2058 }
2059 
2060 /**
2061  * \test Check if we match a source port
2062  */
2063 static int PortTestMatchReal02(void)
2064 {
2065  const char *sig = "alert tcp any 47370 -> any any (msg:\"Nothing..\";"
2066  " content:\"GET\"; sid:1;)";
2067  return PortTestMatchRealWrp(sig, 1);
2068 }
2069 
2070 /**
2071  * \test Check if we match both of them
2072  */
2073 static int PortTestMatchReal03(void)
2074 {
2075  const char *sig = "alert tcp any 47370 -> any 80 (msg:\"Nothing..\";"
2076  " content:\"GET\"; sid:1;)";
2077  return PortTestMatchRealWrp(sig, 1);
2078 }
2079 
2080 /**
2081  * \test Check if we negate dest ports correctly
2082  */
2083 static int PortTestMatchReal04(void)
2084 {
2085  const char *sig = "alert tcp any any -> any !80 (msg:\"Nothing..\";"
2086  " content:\"GET\"; sid:1;)";
2087  return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
2088 }
2089 
2090 /**
2091  * \test Check if we negate source ports correctly
2092  */
2093 static int PortTestMatchReal05(void)
2094 {
2095  const char *sig = "alert tcp any !47370 -> any any (msg:\"Nothing..\";"
2096  " content:\"GET\"; sid:1;)";
2097  return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
2098 }
2099 
2100 /**
2101  * \test Check if we negate both ports correctly
2102  */
2103 static int PortTestMatchReal06(void)
2104 {
2105  const char *sig = "alert tcp any !47370 -> any !80 (msg:\"Nothing..\";"
2106  " content:\"GET\"; sid:1;)";
2107  return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
2108 }
2109 
2110 /**
2111  * \test Check if we match a dest port range
2112  */
2113 static int PortTestMatchReal07(void)
2114 {
2115  const char *sig = "alert tcp any any -> any 70:100 (msg:\"Nothing..\";"
2116  " content:\"GET\"; sid:1;)";
2117  return PortTestMatchRealWrp(sig, 1);
2118 }
2119 
2120 /**
2121  * \test Check if we match a source port range
2122  */
2123 static int PortTestMatchReal08(void)
2124 {
2125  const char *sig = "alert tcp any 47000:50000 -> any any (msg:\"Nothing..\";"
2126  " content:\"GET\"; sid:1;)";
2127  return PortTestMatchRealWrp(sig, 1);
2128 }
2129 
2130 /**
2131  * \test Check if we match both port ranges
2132  */
2133 static int PortTestMatchReal09(void)
2134 {
2135  const char *sig = "alert tcp any 47000:50000 -> any 70:100 (msg:\"Nothing..\";"
2136  " content:\"GET\"; sid:1;)";
2137  return PortTestMatchRealWrp(sig, 1);
2138 }
2139 
2140 /**
2141  * \test Check if we negate a dest port range
2142  */
2143 static int PortTestMatchReal10(void)
2144 {
2145  const char *sig = "alert tcp any any -> any !70:100 (msg:\"Nothing..\";"
2146  " content:\"GET\"; sid:1;)";
2147  return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
2148 }
2149 
2150 /**
2151  * \test Check if we negate a source port range
2152  */
2153 static int PortTestMatchReal11(void)
2154 {
2155  const char *sig = "alert tcp any !47000:50000 -> any any (msg:\"Nothing..\";"
2156  " content:\"GET\"; sid:1;)";
2157  return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
2158 }
2159 
2160 /**
2161  * \test Check if we negate both port ranges
2162  */
2163 static int PortTestMatchReal12(void)
2164 {
2165  const char *sig = "alert tcp any !47000:50000 -> any !70:100 (msg:\"Nothing..\";"
2166  " content:\"GET\"; sid:1;)";
2167  return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
2168 }
2169 
2170 /**
2171  * \test Check if we autocomplete ranges correctly
2172  */
2173 static int PortTestMatchReal13(void)
2174 {
2175  const char *sig = "alert tcp any 47000:50000 -> any !81: (msg:\"Nothing..\";"
2176  " content:\"GET\"; sid:1;)";
2177  return PortTestMatchRealWrp(sig, 1);
2178 }
2179 
2180 /**
2181  * \test Check if we autocomplete ranges correctly
2182  */
2183 static int PortTestMatchReal14(void)
2184 {
2185  const char *sig = "alert tcp any !48000:50000 -> any :100 (msg:\"Nothing..\";"
2186  " content:\"GET\"; sid:1;)";
2187  return PortTestMatchRealWrp(sig, 1);
2188 }
2189 
2190 /**
2191  * \test Check if we autocomplete ranges correctly
2192  */
2193 static int PortTestMatchReal15(void)
2194 {
2195  const char *sig = "alert tcp any :50000 -> any 81:100 (msg:\"Nothing..\";"
2196  " content:\"GET\"; sid:1;)";
2197  return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
2198 }
2199 
2200 /**
2201  * \test Check if we separate ranges correctly
2202  */
2203 static int PortTestMatchReal16(void)
2204 {
2205  const char *sig = "alert tcp any 100: -> any ![0:79,81:65535] (msg:\"Nothing..\";"
2206  " content:\"GET\"; sid:1;)";
2207  return PortTestMatchRealWrp(sig, 1);
2208 }
2209 
2210 /**
2211  * \test Check if we separate ranges correctly
2212  */
2213 static int PortTestMatchReal17(void)
2214 {
2215  const char *sig = "alert tcp any ![0:39999,48000:50000] -> any ![0:80,82:65535] "
2216  "(msg:\"Nothing..\"; content:\"GET\"; sid:1;)";
2217  return (PortTestMatchRealWrp(sig, 1) == 0)? 1 : 0;
2218 }
2219 
2220 /**
2221  * \test Check if we separate ranges correctly
2222  */
2223 static int PortTestMatchReal18(void)
2224 {
2225  const char *sig = "alert tcp any ![0:39999,48000:50000] -> any 80 (msg:\"Nothing"
2226  " at all\"; content:\"GET\"; sid:1;)";
2227  return PortTestMatchRealWrp(sig, 1);
2228 }
2229 
2230 /**
2231  * \test Check if we separate ranges correctly
2232  */
2233 static int PortTestMatchReal19(void)
2234 {
2235  const char *sig = "alert tcp any any -> any 80 (msg:\"Nothing..\";"
2236  " content:\"GET\"; sid:1;)";
2237  return PortTestMatchRealWrp(sig, 1);
2238 }
2239 
2240 static int PortTestMatchDoubleNegation(void)
2241 {
2242  int result = 0;
2243  DetectPort *head = NULL, *nhead = NULL;
2244 
2245  if (DetectPortParseDo(NULL, &head, &nhead, "![!80]", 0, NULL, 0) == -1)
2246  return result;
2247 
2248  result = (head != NULL);
2249  result = (nhead == NULL);
2250 
2251  return result;
2252 }
2253 
2254 // Test that negation is successfully parsed with whitespace for port strings of
2255 // length < 16
2256 static int DetectPortParseDoTest(void)
2257 {
2260  DetectPort *head = NULL;
2261  DetectPort *nhead = NULL;
2262  const char *str = "[30:50, !45]";
2263  int r = DetectPortParseDo(de_ctx, &head, &nhead, str, 0, NULL, 0);
2264 
2265  // Assertions
2266  FAIL_IF_NULL(head);
2267  FAIL_IF_NULL(nhead);
2268  FAIL_IF(r < 0);
2269  FAIL_IF(head->port != 30);
2270  FAIL_IF(head->port2 != 50);
2271  FAIL_IF(nhead->port != 45);
2272  FAIL_IF(nhead->port2 != 45);
2273  DetectPortCleanupList(NULL, head);
2274  DetectPortCleanupList(NULL, nhead);
2275  PASS;
2276 }
2277 
2278 static int DetectPortParseDoTest2(void)
2279 {
2282  DetectPort *head = NULL;
2283  DetectPort *nhead = NULL;
2284  const char *str = "[30:50, !45]";
2285  int r = DetectPortParseDo(de_ctx, &head, &nhead, str, 0, NULL, 0);
2286  FAIL_IF(r < 0);
2287  DetectPortCleanupList(NULL, head);
2288  DetectPortCleanupList(NULL, nhead);
2289  PASS;
2290 }
2291 
2292 // Verifies correct parsing when negation port string length < 16
2293 static int PortParseTestLessThan14Spaces(void)
2294 {
2295  const char *str = " 45";
2296  DetectPort *dp = PortParse(str);
2297  FAIL_IF_NULL(dp);
2298  FAIL_IF(dp->port != 45);
2299  FAIL_IF(dp->port2 != 45);
2300  DetectPortFree(NULL, dp);
2301  PASS;
2302 }
2303 
2304 // Verifies NULL returned when negation port string length == 16
2305 static int PortParseTest14Spaces(void)
2306 {
2307  const char *str = " 45";
2308  DetectPort *dp = PortParse(str);
2309  FAIL_IF_NULL(dp);
2310  FAIL_IF(dp->port != 45);
2311  FAIL_IF(dp->port2 != 45);
2312  DetectPortFree(NULL, dp);
2313  PASS;
2314 }
2315 
2316 // Verifies NULL returned when negation port string length >= 16
2317 static int PortParseTestMoreThan14Spaces(void)
2318 {
2319  const char *str = " 45";
2320  DetectPort *dp = PortParse(str);
2321  FAIL_IF_NULL(dp);
2322  FAIL_IF(dp->port != 45);
2323  FAIL_IF(dp->port2 != 45);
2324  DetectPortFree(NULL, dp);
2325  PASS;
2326 }
2327 
2328 void DetectPortTests(void)
2329 {
2330  UtRegisterTest("PortTestParse01", PortTestParse01);
2331  UtRegisterTest("PortTestParse02", PortTestParse02);
2332  UtRegisterTest("PortTestParse03", PortTestParse03);
2333  UtRegisterTest("PortTestParse04", PortTestParse04);
2334  UtRegisterTest("PortTestParse05", PortTestParse05);
2335  UtRegisterTest("PortTestParse07", PortTestParse07);
2336  UtRegisterTest("PortTestParse08", PortTestParse08);
2337  UtRegisterTest("PortTestParse09", PortTestParse09);
2338  UtRegisterTest("PortTestParse10", PortTestParse10);
2339  UtRegisterTest("PortTestParse11", PortTestParse11);
2340  UtRegisterTest("PortTestParse12", PortTestParse12);
2341  UtRegisterTest("PortTestParse13", PortTestParse13);
2342  UtRegisterTest("PortTestParse14", PortTestParse14);
2343  UtRegisterTest("PortTestParse15", PortTestParse15);
2344  UtRegisterTest("PortTestParse16", PortTestParse16);
2345  UtRegisterTest("PortTestFunctions01", PortTestFunctions01);
2346  UtRegisterTest("PortTestFunctions02", PortTestFunctions02);
2347  UtRegisterTest("PortTestFunctions03", PortTestFunctions03);
2348  UtRegisterTest("PortTestFunctions04", PortTestFunctions04);
2349  UtRegisterTest("PortTestFunctions07", PortTestFunctions07);
2350  UtRegisterTest("PortTestMatchReal01", PortTestMatchReal01);
2351  UtRegisterTest("PortTestMatchReal02", PortTestMatchReal02);
2352  UtRegisterTest("PortTestMatchReal03", PortTestMatchReal03);
2353  UtRegisterTest("PortTestMatchReal04", PortTestMatchReal04);
2354  UtRegisterTest("PortTestMatchReal05", PortTestMatchReal05);
2355  UtRegisterTest("PortTestMatchReal06", PortTestMatchReal06);
2356  UtRegisterTest("PortTestMatchReal07", PortTestMatchReal07);
2357  UtRegisterTest("PortTestMatchReal08", PortTestMatchReal08);
2358  UtRegisterTest("PortTestMatchReal09", PortTestMatchReal09);
2359  UtRegisterTest("PortTestMatchReal10", PortTestMatchReal10);
2360  UtRegisterTest("PortTestMatchReal11", PortTestMatchReal11);
2361  UtRegisterTest("PortTestMatchReal12", PortTestMatchReal12);
2362  UtRegisterTest("PortTestMatchReal13", PortTestMatchReal13);
2363  UtRegisterTest("PortTestMatchReal14", PortTestMatchReal14);
2364  UtRegisterTest("PortTestMatchReal15", PortTestMatchReal15);
2365  UtRegisterTest("PortTestMatchReal16", PortTestMatchReal16);
2366  UtRegisterTest("PortTestMatchReal17", PortTestMatchReal17);
2367  UtRegisterTest("PortTestMatchReal18", PortTestMatchReal18);
2368  UtRegisterTest("PortTestMatchReal19", PortTestMatchReal19);
2369  UtRegisterTest("PortTestMatchDoubleNegation", PortTestMatchDoubleNegation);
2370  UtRegisterTest("DetectPortParseDoTest", DetectPortParseDoTest);
2371  UtRegisterTest("DetectPortParseDoTest2", DetectPortParseDoTest2);
2372  UtRegisterTest("PortParseTestLessThan14Spaces", PortParseTestLessThan14Spaces);
2373  UtRegisterTest("PortParseTest14Spaces", PortParseTest14Spaces);
2374  UtRegisterTest("PortParseTestMoreThan14Spaces", PortParseTestMoreThan14Spaces);
2375 }
2376 
2377 #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
PacketRecycle
void PacketRecycle(Packet *p)
Definition: packet.c:151
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
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:810
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:547
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
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:691
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:2594
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