Coverage Report

Created: 2025-11-16 07:09

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