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