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