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