• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 22618661228

02 Mar 2026 09:33PM UTC coverage: 42.258% (-34.4%) from 76.611%
22618661228

push

github

victorjulien
github-actions: bump actions/download-artifact from 7.0.0 to 8.0.0

Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 7.0.0 to 8.0.0.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/37930b1c2...70fc10c6e)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: 8.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

91511 of 216553 relevant lines covered (42.26%)

3416852.41 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

7.12
/src/detect-engine-iponly.c
1
/* Copyright (C) 2007-2022 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
 * \author Pablo Rincon Crespo <pablo.rincon.crespo@gmail.com>
23
 *
24
 * Signatures that only inspect IP addresses are processed here
25
 * We use radix trees for src dst ipv4 and ipv6 addresses
26
 * This radix trees hold information for subnets and hosts in a
27
 * hierarchical distribution
28
 */
29

30
#include "suricata-common.h"
31
#include "detect.h"
32
#include "decode.h"
33
#include "flow.h"
34

35
#include "detect-parse.h"
36
#include "detect-engine.h"
37

38
#include "detect-engine-siggroup.h"
39
#include "detect-engine-address.h"
40
#include "detect-engine-proto.h"
41
#include "detect-engine-port.h"
42
#include "detect-engine-mpm.h"
43
#include "detect-engine-build.h"
44

45
#include "detect-engine-threshold.h"
46
#include "detect-engine-iponly.h"
47
#include "detect-threshold.h"
48
#include "util-classification-config.h"
49
#include "util-rule-vars.h"
50
#include "detect-engine-alert.h"
51

52
#include "flow-util.h"
53
#include "util-debug.h"
54
#include "util-unittest.h"
55
#include "util-unittest-helper.h"
56
#include "util-print.h"
57
#include "util-byte.h"
58
#include "util-profiling.h"
59
#include "util-validate.h"
60
#include "util-cidr.h"
61

62
#ifdef OS_WIN32
63
#include <winsock.h>
64
#else
65
#include <netinet/in.h>
66
#endif /* OS_WIN32 */
67

68
/**
69
 * \brief This function creates a new IPOnlyCIDRItem
70
 *
71
 * \retval IPOnlyCIDRItem address of the new instance
72
 */
73
static IPOnlyCIDRItem *IPOnlyCIDRItemNew(void)
74
{
×
75
    SCEnter();
×
76
    IPOnlyCIDRItem *item = NULL;
×
77

78
    item = SCCalloc(1, sizeof(IPOnlyCIDRItem));
×
79
    if (unlikely(item == NULL))
×
80
        SCReturnPtr(NULL, "IPOnlyCIDRItem");
×
81

82
    SCReturnPtr(item, "IPOnlyCIDRItem");
×
83
}
×
84

85
/**
86
 * \brief Compares two list items
87
 *
88
 * \retval An integer less than, equal to, or greater than zero if lhs is
89
 *         considered to be respectively less than, equal to, or greater than
90
 *         rhs.
91
 */
92
static int IPOnlyCIDRItemCompareReal(const IPOnlyCIDRItem *lhs, const IPOnlyCIDRItem *rhs)
93
{
×
94
    if (lhs->netmask == rhs->netmask) {
×
95
        uint8_t i = 0;
×
96
        for (; i < lhs->netmask / 32 || i < 1; i++) {
×
97
            if (lhs->ip[i] < rhs->ip[i])
×
98
                return -1;
×
99
            if (lhs->ip[i] > rhs->ip[i])
×
100
                return 1;
×
101
        }
×
102
        return 0;
×
103
    }
×
104

105
    return lhs->netmask < rhs->netmask ? -1 : 1;
×
106
}
×
107

108
static int IPOnlyCIDRItemCompare(const void *lhsv, const void *rhsv)
109
{
×
110
    const IPOnlyCIDRItem *lhs = *(const IPOnlyCIDRItem **)lhsv;
×
111
    const IPOnlyCIDRItem *rhs = *(const IPOnlyCIDRItem **)rhsv;
×
112

113
    return IPOnlyCIDRItemCompareReal(lhs, rhs);
×
114
}
×
115

116
static void IPOnlyCIDRListQSort(IPOnlyCIDRItem **head)
117
{
14✔
118
    if (unlikely(head == NULL || *head == NULL))
14✔
119
        return;
14✔
120

121
    // First count the number of elements in the list
122
    size_t len = 0;
×
123
    IPOnlyCIDRItem *curr = *head;
×
124

125
    while (curr) {
×
126
        curr = curr->next;
×
127
        len++;
×
128
    }
×
129

130
    // Place a pointer to the list item in an array for sorting
131
    IPOnlyCIDRItem **tmp = SCMalloc(len * sizeof(IPOnlyCIDRItem *));
×
132

133
    if (unlikely(tmp == NULL)) {
×
134
        SCLogError("Failed to allocate enough memory to sort IP-only CIDR items.");
×
135
        return;
×
136
    }
×
137

138
    curr = *head;
×
139
    for (size_t i = 0; i < len; i++) {
×
140
        tmp[i] = curr;
×
141
        curr = curr->next;
×
142
    }
×
143

144
    // Perform the sort using the qsort algorithm
145
    qsort(tmp, len, sizeof(IPOnlyCIDRItem *), IPOnlyCIDRItemCompare);
×
146

147
    // Update the links to the next element
148
    *head = tmp[0];
×
149

150
    for (size_t i = 0; i + 1 < len; i++) {
×
151
        tmp[i]->next = tmp[i + 1];
×
152
    }
×
153

154
    tmp[len - 1]->next = NULL;
×
155

156
    SCFree(tmp);
×
157
}
×
158

159
//declaration for using it already
160
static IPOnlyCIDRItem *IPOnlyCIDRItemInsert(IPOnlyCIDRItem *head,
161
                                            IPOnlyCIDRItem *item);
162

163
static int InsertRange(
164
        IPOnlyCIDRItem **pdd, IPOnlyCIDRItem *dd, const uint32_t first_in, const uint32_t last_in)
165
{
×
166
    DEBUG_VALIDATE_BUG_ON(dd == NULL);
×
167
    DEBUG_VALIDATE_BUG_ON(pdd == NULL);
×
168

169
    uint32_t first = first_in;
×
170
    uint32_t last = last_in;
×
171

172
    dd->netmask = 32;
×
173
    /* Find the maximum netmask starting from current address first
174
     * and not crossing last.
175
     * To extend the mask, we need to start from a power of 2.
176
     * And we need to pay attention to unsigned overflow back to 0.0.0.0
177
     */
178
    while (dd->netmask > 0 && (first & (1UL << (32 - dd->netmask))) == 0 &&
×
179
            first + (1UL << (32 - (dd->netmask - 1))) - 1 <= last) {
×
180
        dd->netmask--;
×
181
    }
×
182
    dd->ip[0] = htonl(first);
×
183
    first += 1UL << (32 - dd->netmask);
×
184
    // case whatever-255.255.255.255 looping to 0.0.0.0/0
185
    while (first <= last && first != 0) {
×
186
        IPOnlyCIDRItem *new = IPOnlyCIDRItemNew();
×
187
        if (new == NULL)
×
188
            goto error;
×
189
        new->negated = dd->negated;
×
190
        new->family = dd->family;
×
191
        new->netmask = 32;
×
192
        while (new->netmask > 0 && (first & (1UL << (32 - new->netmask))) == 0 &&
×
193
                first + (1UL << (32 - (new->netmask - 1))) - 1 <= last) {
×
194
            new->netmask--;
×
195
        }
×
196
        new->ip[0] = htonl(first);
×
197
        first += 1UL << (32 - new->netmask);
×
198
        dd = IPOnlyCIDRItemInsert(dd, new);
×
199
    }
×
200
    // update head of list
201
    *pdd = dd;
×
202
    return 0;
×
203
error:
×
204
    return -1;
×
205
}
×
206

207
/**
208
 * \internal
209
 * \brief Parses an ipv4/ipv6 address string and updates the result into the
210
 *        IPOnlyCIDRItem instance sent as the argument.
211
 *
212
 * \param pdd Double pointer to the IPOnlyCIDRItem instance which should be updated
213
 *            with the address (in cidr) details from the parsed ip string.
214
 * \param str Pointer to address string that has to be parsed.
215
 *
216
 * \retval  0 On successfully parsing the address string.
217
 * \retval -1 On failure.
218
 */
219
static int IPOnlyCIDRItemParseSingle(IPOnlyCIDRItem **pdd, const char *str)
220
{
×
221
    char buf[256] = "";
×
222
    char *ip = NULL, *ip2 = NULL;
×
223
    char *mask = NULL;
×
224
    int r = 0;
×
225
    IPOnlyCIDRItem *dd = *pdd;
×
226

227
    while (*str != '\0' && *str == ' ')
×
228
        str++;
×
229

230
    SCLogDebug("str %s", str);
×
231
    strlcpy(buf, str, sizeof(buf));
×
232
    ip = buf;
×
233

234
    /* first handle 'any' */
235
    if (strcasecmp(str, "any") == 0) {
×
236
        /* if any, insert 0.0.0.0/0 and ::/0 as well */
237
        SCLogDebug("adding 0.0.0.0/0 and ::/0 as we\'re handling \'any\'");
×
238

239
        IPOnlyCIDRItemParseSingle(&dd, "0.0.0.0/0");
×
240
        BUG_ON(dd->family == 0);
×
241

242
        dd->next = IPOnlyCIDRItemNew();
×
243
        if (dd->next == NULL)
×
244
            goto error;
×
245

246
        IPOnlyCIDRItemParseSingle(&dd->next, "::/0");
×
247
        BUG_ON(dd->family == 0);
×
248

249
        SCLogDebug("address is \'any\'");
×
250
        return 0;
×
251
    }
×
252

253
    /* handle the negation case */
254
    if (ip[0] == '!') {
×
255
        dd->negated = (dd->negated)? 0 : 1;
×
256
        ip++;
×
257
    }
×
258

259
    /* see if the address is an ipv4 or ipv6 address */
260
    if ((strchr(str, ':')) == NULL) {
×
261
        /* IPv4 Address */
262
        struct in_addr in;
×
263

264
        dd->family = AF_INET;
×
265

266
        if ((mask = strchr(ip, '/')) != NULL) {
×
267
            /* 1.2.3.4/xxx format (either dotted or cidr notation */
268
            ip[mask - ip] = '\0';
×
269
            mask++;
×
270
            uint32_t netmask = 0;
×
271
            size_t u = 0;
×
272

273
            if ((strchr (mask, '.')) == NULL) {
×
274
                /* 1.2.3.4/24 format */
275

276
                for (u = 0; u < strlen(mask); u++) {
×
277
                    if(!isdigit((unsigned char)mask[u]))
×
278
                        goto error;
×
279
                }
×
280

281
                uint8_t cidr;
×
282
                if (StringParseU8RangeCheck(&cidr, 10, 0, (const char *)mask, 0, 32) <= 0)
×
283
                    goto error;
×
284

285
                dd->netmask = cidr;
×
286
                netmask = CIDRGet(cidr);
×
287
            } else {
×
288
                /* 1.2.3.4/255.255.255.0 format */
289
                r = inet_pton(AF_INET, mask, &in);
×
290
                if (r <= 0)
×
291
                    goto error;
×
292

293
                int cidr = CIDRFromMask(in.s_addr);
×
294
                if (cidr < 0)
×
295
                    goto error;
×
296

297
                dd->netmask = (uint8_t)cidr;
×
298
            }
×
299

300
            r = inet_pton(AF_INET, ip, &in);
×
301
            if (r <= 0)
×
302
                goto error;
×
303

304
            dd->ip[0] = in.s_addr & netmask;
×
305

306
        } else if ((ip2 = strchr(ip, '-')) != NULL) {
×
307
            /* 1.2.3.4-1.2.3.6 range format */
308
            ip[ip2 - ip] = '\0';
×
309
            ip2++;
×
310

311
            uint32_t first, last;
×
312

313
            r = inet_pton(AF_INET, ip, &in);
×
314
            if (r <= 0)
×
315
                goto error;
×
316
            first = SCNtohl(in.s_addr);
×
317

318
            r = inet_pton(AF_INET, ip2, &in);
×
319
            if (r <= 0)
×
320
                goto error;
×
321
            last = SCNtohl(in.s_addr);
×
322

323
            /* a > b is illegal, a = b is ok */
324
            if (first > last)
×
325
                goto error;
×
326

327
            SCLogDebug("Creating CIDR range for [%s - %s]", ip, ip2);
×
328
            return InsertRange(pdd, dd, first, last);
×
329
        } else {
×
330
            /* 1.2.3.4 format */
331
            r = inet_pton(AF_INET, ip, &in);
×
332
            if (r <= 0)
×
333
                goto error;
×
334

335
            /* single host */
336
            dd->ip[0] = in.s_addr;
×
337
            dd->netmask = 32;
×
338
        }
×
339
    } else {
×
340
        /* IPv6 Address */
341
        struct in6_addr in6, mask6;
×
342
        uint32_t ip6addr[4], netmask[4];
×
343

344
        dd->family = AF_INET6;
×
345

346
        if ((mask = strchr(ip, '/')) != NULL)  {
×
347
            mask[0] = '\0';
×
348
            mask++;
×
349

350
            r = inet_pton(AF_INET6, ip, &in6);
×
351
            if (r <= 0)
×
352
                goto error;
×
353

354
            /* Format is cidr val */
355
            if (StringParseU8RangeCheck(&dd->netmask, 10, 0,
×
356
                                        (const char *)mask, 0, 128) < 0) {
×
357
                goto error;
×
358
            }
×
359

360
            memcpy(&ip6addr, &in6.s6_addr, sizeof(ip6addr));
×
361
            CIDRGetIPv6(dd->netmask, &mask6);
×
362
            memcpy(&netmask, &mask6.s6_addr, sizeof(netmask));
×
363

364
            dd->ip[0] = ip6addr[0] & netmask[0];
×
365
            dd->ip[1] = ip6addr[1] & netmask[1];
×
366
            dd->ip[2] = ip6addr[2] & netmask[2];
×
367
            dd->ip[3] = ip6addr[3] & netmask[3];
×
368
        } else {
×
369
            r = inet_pton(AF_INET6, ip, &in6);
×
370
            if (r <= 0)
×
371
                goto error;
×
372

373
            memcpy(dd->ip, &in6.s6_addr, sizeof(dd->ip));
×
374
            dd->netmask = 128;
×
375
        }
×
376

377
    }
×
378

379
    BUG_ON(dd->family == 0);
×
380
    return 0;
×
381

382
error:
×
383
    return -1;
×
384
}
×
385

386
/**
387
 * \brief Setup a single address string, parse it and add the resulting
388
 *        Address items in cidr format to the list of gh
389
 *
390
 * \param gh Pointer to the IPOnlyCIDRItem list Head to which the
391
 *           resulting Address-Range(s) from the parsed ip string has to
392
 *           be added.
393
 * \param s  Pointer to the ip address string to be parsed.
394
 *
395
 * \retval  0 On success.
396
 * \retval -1 On failure.
397
 */
398
static int IPOnlyCIDRItemSetup(IPOnlyCIDRItem **gh, char *s)
399
{
×
400
    SCLogDebug("gh %p, s %s", *gh, s);
×
401

402
    /* parse the address */
403
    if (IPOnlyCIDRItemParseSingle(gh, s) == -1) {
×
404
        SCLogError("address parsing error \"%s\"", s);
×
405
        goto error;
×
406
    }
×
407

408
    return 0;
×
409

410
error:
×
411
    return -1;
×
412
}
×
413

414
/**
415
 * \brief This function insert a IPOnlyCIDRItem
416
 *        to a list of IPOnlyCIDRItems
417
 * \param head Pointer to the head of IPOnlyCIDRItems list
418
 * \param item Pointer to the item to insert in the list
419
 *
420
 * \retval IPOnlyCIDRItem address of the new head if apply
421
 */
422
static IPOnlyCIDRItem *IPOnlyCIDRItemInsertReal(IPOnlyCIDRItem *head,
423
                                         IPOnlyCIDRItem *item)
424
{
×
425
    if (item == NULL)
×
426
        return head;
×
427

428
    /* Always insert item as head */
429
    item->next = head;
×
430
    return item;
×
431
}
×
432

433
/**
434
 * \brief This function insert a IPOnlyCIDRItem list
435
 *        to a list of IPOnlyCIDRItems sorted by netmask
436
 *        ascending
437
 * \param head Pointer to the head of IPOnlyCIDRItems list
438
 * \param item Pointer to the list of items to insert in the list
439
 *
440
 * \retval IPOnlyCIDRItem address of the new head if apply
441
 */
442
static IPOnlyCIDRItem *IPOnlyCIDRItemInsert(IPOnlyCIDRItem *head,
443
                                     IPOnlyCIDRItem *item)
444
{
×
445
    IPOnlyCIDRItem *it, *prev = NULL;
×
446

447
    /* The first element */
448
    if (head == NULL) {
×
449
        SCLogDebug("Head is NULL to insert item (%p)",item);
×
450
        return item;
×
451
    }
×
452

453
    if (item == NULL) {
×
454
        SCLogDebug("Item is NULL");
×
455
        return head;
×
456
    }
×
457

458
    SCLogDebug("Inserting item(%p)->netmask %u head %p", item, item->netmask, head);
×
459

460
    prev = item;
×
461
    while (prev != NULL) {
×
462
        it = prev->next;
×
463

464
        /* Separate from the item list */
465
        prev->next = NULL;
×
466

467
        //SCLogDebug("Before:");
468
        //IPOnlyCIDRListPrint(head);
469
        head = IPOnlyCIDRItemInsertReal(head, prev);
×
470
        //SCLogDebug("After:");
471
        //IPOnlyCIDRListPrint(head);
472
        prev = it;
×
473
    }
×
474

475
    return head;
×
476
}
×
477

478
/**
479
 * \brief This function free a IPOnlyCIDRItem list
480
 * \param tmphead Pointer to the list
481
 */
482
void IPOnlyCIDRListFree(IPOnlyCIDRItem *tmphead)
483
{
×
484
    SCEnter();
×
485
#ifdef DEBUG
486
    uint32_t i = 0;
487
#endif
488
    IPOnlyCIDRItem *it, *next = NULL;
×
489

490
    if (tmphead == NULL) {
×
491
        SCLogDebug("temphead is NULL");
×
492
        return;
×
493
    }
×
494

495
    it = tmphead;
×
496
    next = it->next;
×
497

498
    while (it != NULL) {
×
499
#ifdef DEBUG
500
        i++;
501
        SCLogDebug("Item(%p) %"PRIu32" removed", it, i);
502
#endif
503
        SCFree(it);
×
504
        it = next;
×
505

506
        if (next != NULL)
×
507
            next = next->next;
×
508
    }
×
509
    SCReturn;
×
510
}
×
511

512
/**
513
 * \brief This function update a list of IPOnlyCIDRItems
514
 *        setting the signature internal id (signum) to "i"
515
 *
516
 * \param tmphead Pointer to the list
517
 * \param i number of signature internal id
518
 */
519
static void IPOnlyCIDRListSetSigNum(IPOnlyCIDRItem *tmphead, SigIntId i)
520
{
×
521
    while (tmphead != NULL) {
×
522
        tmphead->signum = i;
×
523
        tmphead = tmphead->next;
×
524
    }
×
525
}
×
526

527
#ifdef UNITTESTS
528
/**
529
 * \brief This function print a IPOnlyCIDRItem list
530
 * \param tmphead Pointer to the head of IPOnlyCIDRItems list
531
 */
532
static void IPOnlyCIDRListPrint(IPOnlyCIDRItem *tmphead)
533
{
534
#ifdef DEBUG
535
    uint32_t i = 0;
536

537
    while (tmphead != NULL) {
538
        i++;
539
        SCLogDebug("Item %"PRIu32" has netmask %"PRIu8" negated:"
540
                   " %s; IP: %s; signum: %"PRIu32, i, tmphead->netmask,
541
                   (tmphead->negated) ? "yes":"no",
542
                   inet_ntoa(*(struct in_addr*)&tmphead->ip[0]),
543
                   tmphead->signum);
544
        tmphead = tmphead->next;
545
    }
546
#endif
547
}
548
#endif
549

550
/** \brief user data for storing signature id's in the radix tree
551
 *
552
 *  Bit array representing signature internal id's (Signature::num).
553
 */
554
typedef struct SigNumArray_ {
555
    uint8_t *array; /* bit array of sig nums */
556
    uint32_t size;  /* size in bytes of the array */
557
} SigNumArray;
558

559
/**
560
 * \brief This function print a SigNumArray, it's used with the
561
 *        radix tree print function to help debugging
562
 * \param tmp Pointer to the head of SigNumArray
563
 */
564
static void SigNumArrayPrint(void *tmp)
565
{
×
566
    SigNumArray *sna = (SigNumArray *)tmp;
×
567
    for (uint32_t u = 0; u < sna->size; u++) {
×
568
        uint8_t bitarray = sna->array[u];
×
569
        for (uint8_t i = 0; i < 8; i++) {
×
570
            if (bitarray & 0x01)
×
571
                printf("%" PRIu32 " ", u * 8 + i);
×
572
            bitarray = bitarray >> 1;
×
573
        }
×
574
    }
×
575
}
×
576

577
/**
578
 * \brief This function creates a new SigNumArray with the
579
 *        size fixed to the io_ctx->max_idx
580
 * \param de_ctx Pointer to the current detection context
581
 * \param io_ctx Pointer to the current ip only context
582
 *
583
 * \retval SigNumArray address of the new instance
584
 */
585
static SigNumArray *SigNumArrayNew(DetectEngineCtx *de_ctx,
586
                            DetectEngineIPOnlyCtx *io_ctx)
587
{
×
588
    SigNumArray *new = SCCalloc(1, sizeof(SigNumArray));
×
589

590
    if (unlikely(new == NULL)) {
×
591
        FatalError("Fatal error encountered in SigNumArrayNew. Exiting...");
×
592
    }
×
593

594
    new->array = SCCalloc(1, io_ctx->max_idx / 8 + 1);
×
595
    if (new->array == NULL) {
×
596
       exit(EXIT_FAILURE);
×
597
    }
×
598

599
    new->size = io_ctx->max_idx / 8 + 1;
×
600

601
    SCLogDebug("max idx= %u", io_ctx->max_idx);
×
602

603
    return new;
×
604
}
×
605

606
/**
607
 * \brief This function creates a new SigNumArray with the
608
 *        same data as the argument
609
 *
610
 * \param orig Pointer to the original SigNumArray to copy
611
 *
612
 * \retval SigNumArray address of the new instance
613
 */
614
static SigNumArray *SigNumArrayCopy(SigNumArray *orig)
615
{
×
616
    SigNumArray *new = SCCalloc(1, sizeof(SigNumArray));
×
617

618
    if (unlikely(new == NULL)) {
×
619
        FatalError("Fatal error encountered in SigNumArrayCopy. Exiting...");
×
620
    }
×
621

622
    new->size = orig->size;
×
623

624
    new->array = SCMalloc(orig->size);
×
625
    if (new->array == NULL) {
×
626
        exit(EXIT_FAILURE);
×
627
    }
×
628

629
    memcpy(new->array, orig->array, orig->size);
×
630
    return new;
×
631
}
×
632

633
/**
634
 * \brief This function free() a SigNumArray
635
 * \param orig Pointer to the original SigNumArray to copy
636
 */
637
static void SigNumArrayFree(void *tmp)
638
{
×
639
    SigNumArray *sna = (SigNumArray *)tmp;
×
640

641
    if (sna == NULL)
×
642
        return;
×
643

644
    if (sna->array != NULL)
×
645
        SCFree(sna->array);
×
646

647
    SCFree(sna);
×
648
}
×
649

650
/**
651
 * \brief This function parses and return a list of IPOnlyCIDRItem
652
 *
653
 * \param s Pointer to the string of the addresses
654
 *          (in the format of signatures)
655
 * \param negate flag to indicate if all this string is negated or not
656
 *
657
 * \retval 0 if success
658
 * \retval -1 if fails
659
 */
660
static IPOnlyCIDRItem *IPOnlyCIDRListParse2(
661
        const DetectEngineCtx *de_ctx, const char *s, int negate)
662
{
×
663
    size_t x = 0;
×
664
    size_t u = 0;
×
665
    int o_set = 0, n_set = 0, d_set = 0;
×
666
    int depth = 0;
×
667
    size_t size = strlen(s);
×
668
    char address[8196] = "";
×
669
    const char *rule_var_address = NULL;
×
670
    char *temp_rule_var_address = NULL;
×
671
    IPOnlyCIDRItem *head;
×
672
    IPOnlyCIDRItem *subhead;
×
673
    head = subhead = NULL;
×
674

675
    SCLogDebug("s %s negate %s", s, negate ? "true" : "false");
×
676

677
    for (u = 0, x = 0; u < size && x < sizeof(address); u++) {
×
678
        address[x] = s[u];
×
679
        x++;
×
680

681
        if (!o_set && s[u] == '!') {
×
682
            n_set = 1;
×
683
            x--;
×
684
        } else if (s[u] == '[') {
×
685
            if (!o_set) {
×
686
                o_set = 1;
×
687
                x = 0;
×
688
            }
×
689
            depth++;
×
690
        } else if (s[u] == ']') {
×
691
            if (depth == 1) {
×
692
                address[x - 1] = '\0';
×
693
                x = 0;
×
694

695
                if ( (subhead = IPOnlyCIDRListParse2(de_ctx, address,
×
696
                                                (negate + n_set) % 2)) == NULL)
×
697
                    goto error;
×
698

699
                head = IPOnlyCIDRItemInsert(head, subhead);
×
700
                n_set = 0;
×
701
            }
×
702
            depth--;
×
703
        } else if (depth == 0 && s[u] == ',') {
×
704
            if (o_set == 1) {
×
705
                o_set = 0;
×
706
            } else if (d_set == 1) {
×
707
                address[x - 1] = '\0';
×
708

709
                rule_var_address = SCRuleVarsGetConfVar(de_ctx, address,
×
710
                                                  SC_RULE_VARS_ADDRESS_GROUPS);
×
711
                if (rule_var_address == NULL)
×
712
                    goto error;
×
713

714
                if ((negate + n_set) % 2) {
×
715
                    /* add +1 to safisfy gcc 15 + -Wformat-truncation=2 */
716
                    const size_t str_size = strlen(rule_var_address) + 3 + 1;
×
717
                    temp_rule_var_address = SCMalloc(str_size);
×
718
                    if (unlikely(temp_rule_var_address == NULL)) {
×
719
                        goto error;
×
720
                    }
×
721

722
                    snprintf(temp_rule_var_address, str_size, "[%s]", rule_var_address);
×
723
                } else {
×
724
                    temp_rule_var_address = SCStrdup(rule_var_address);
×
725
                    if (unlikely(temp_rule_var_address == NULL)) {
×
726
                        goto error;
×
727
                    }
×
728
                }
×
729

730
                subhead = IPOnlyCIDRListParse2(de_ctx, temp_rule_var_address,
×
731
                                               (negate + n_set) % 2);
×
732
                head = IPOnlyCIDRItemInsert(head, subhead);
×
733

734
                d_set = 0;
×
735
                n_set = 0;
×
736

737
                SCFree(temp_rule_var_address);
×
738

739
            } else {
×
740
                address[x - 1] = '\0';
×
741

742
                subhead = IPOnlyCIDRItemNew();
×
743
                if (subhead == NULL)
×
744
                    goto error;
×
745

746
                if (!((negate + n_set) % 2))
×
747
                    subhead->negated = 0;
×
748
                else
×
749
                    subhead->negated = 1;
×
750

751
                if (IPOnlyCIDRItemSetup(&subhead, address) < 0) {
×
752
                    IPOnlyCIDRListFree(subhead);
×
753
                    subhead = NULL;
×
754
                    goto error;
×
755
                }
×
756
                head = IPOnlyCIDRItemInsert(head, subhead);
×
757

758
                n_set = 0;
×
759
            }
×
760
            x = 0;
×
761
        } else if (depth == 0 && s[u] == '$') {
×
762
            d_set = 1;
×
763
        } else if (depth == 0 && u == size - 1) {
×
764
            if (x == sizeof(address)) {
×
765
                address[x - 1] = '\0';
×
766
            } else {
×
767
                address[x] = '\0';
×
768
            }
×
769
            x = 0;
×
770

771
            if (d_set == 1) {
×
772
                rule_var_address = SCRuleVarsGetConfVar(de_ctx, address,
×
773
                                                    SC_RULE_VARS_ADDRESS_GROUPS);
×
774
                if (rule_var_address == NULL)
×
775
                    goto error;
×
776

777
                if ((negate + n_set) % 2) {
×
778
                    /* add +1 to safisfy gcc 15 + -Wformat-truncation=2 */
779
                    const size_t str_size = strlen(rule_var_address) + 3 + 1;
×
780
                    temp_rule_var_address = SCMalloc(str_size);
×
781
                    if (unlikely(temp_rule_var_address == NULL)) {
×
782
                        goto error;
×
783
                    }
×
784
                    snprintf(temp_rule_var_address, str_size, "[%s]", rule_var_address);
×
785
                } else {
×
786
                    temp_rule_var_address = SCStrdup(rule_var_address);
×
787
                    if (unlikely(temp_rule_var_address == NULL)) {
×
788
                        goto error;
×
789
                    }
×
790
                }
×
791
                subhead = IPOnlyCIDRListParse2(de_ctx, temp_rule_var_address,
×
792
                                               (negate + n_set) % 2);
×
793
                head = IPOnlyCIDRItemInsert(head, subhead);
×
794

795
                d_set = 0;
×
796

797
                SCFree(temp_rule_var_address);
×
798
            } else {
×
799
                subhead = IPOnlyCIDRItemNew();
×
800
                if (subhead == NULL)
×
801
                    goto error;
×
802

803
                if (!((negate + n_set) % 2))
×
804
                    subhead->negated = 0;
×
805
                else
×
806
                    subhead->negated = 1;
×
807

808
                if (IPOnlyCIDRItemSetup(&subhead, address) < 0) {
×
809
                    IPOnlyCIDRListFree(subhead);
×
810
                    subhead = NULL;
×
811
                    goto error;
×
812
                }
×
813
                head = IPOnlyCIDRItemInsert(head, subhead);
×
814
            }
×
815
            n_set = 0;
×
816
        }
×
817
    }
×
818

819
    return head;
×
820

821
error:
×
822
    SCLogError("Error parsing addresses");
×
823
    return head;
×
824
}
×
825

826

827
/**
828
 * \brief Parses an address group sent as a character string and updates the
829
 *        IPOnlyCIDRItem list
830
 *
831
 * \param gh  Pointer to the IPOnlyCIDRItem list
832
 * \param str Pointer to the character string containing the address group
833
 *            that has to be parsed.
834
 *
835
 * \retval  0 On success.
836
 * \retval -1 On failure.
837
 */
838
static int IPOnlyCIDRListParse(const DetectEngineCtx *de_ctx, IPOnlyCIDRItem **gh, const char *str)
839
{
×
840
    SCLogDebug("gh %p, str %s", gh, str);
×
841

842
    if (gh == NULL)
×
843
        goto error;
×
844

845
    *gh = IPOnlyCIDRListParse2(de_ctx, str, 0);
×
846
    if (*gh == NULL) {
×
847
        SCLogDebug("IPOnlyCIDRListParse2 returned null");
×
848
        goto error;
×
849
    }
×
850

851
    return 0;
×
852

853
error:
×
854
    return -1;
×
855
}
×
856

857
/**
858
 * \brief Parses an address group sent as a character string and updates the
859
 *        IPOnlyCIDRItem lists src and dst of the Signature *s
860
 *
861
 * \param s Pointer to the signature structure
862
 * \param addrstr Pointer to the character string containing the address group
863
 *            that has to be parsed.
864
 * \param flag to indicate if we are parsing the src string or the dst string
865
 *
866
 * \retval  0 On success.
867
 * \retval -1 On failure.
868
 */
869
int IPOnlySigParseAddress(const DetectEngineCtx *de_ctx,
870
                          Signature *s, const char *addrstr, char flag)
871
{
×
872
    SCLogDebug("Address Group \"%s\" to be parsed now", addrstr);
×
873

874
    /* pass on to the address(list) parser */
875
    if (flag == 0) {
×
876
        if (strcasecmp(addrstr, "any") == 0) {
×
877
            s->flags |= SIG_FLAG_SRC_ANY;
×
878
            if (IPOnlyCIDRListParse(de_ctx, &s->init_data->cidr_src, "[0.0.0.0/0,::/0]") < 0)
×
879
                goto error;
×
880

881
        } else if (IPOnlyCIDRListParse(de_ctx, &s->init_data->cidr_src, (char *)addrstr) < 0) {
×
882
            goto error;
×
883
        }
×
884

885
        /* IPOnlyCIDRListPrint(s->CidrSrc); */
886
    } else {
×
887
        if (strcasecmp(addrstr, "any") == 0) {
×
888
            s->flags |= SIG_FLAG_DST_ANY;
×
889
            if (IPOnlyCIDRListParse(de_ctx, &s->init_data->cidr_dst, "[0.0.0.0/0,::/0]") < 0)
×
890
                goto error;
×
891

892
        } else if (IPOnlyCIDRListParse(de_ctx, &s->init_data->cidr_dst, (char *)addrstr) < 0) {
×
893
            goto error;
×
894
        }
×
895

896
        /* IPOnlyCIDRListPrint(s->CidrDst); */
897
    }
×
898

899
    return 0;
×
900

901
error:
×
902
    SCLogError("failed to parse addresses");
×
903
    return -1;
×
904
}
×
905

906
static const SCRadix4Config iponly_radix4_config = { SigNumArrayFree, SigNumArrayPrint };
907
static const SCRadix6Config iponly_radix6_config = { SigNumArrayFree, SigNumArrayPrint };
908

909
/**
910
 * \brief Setup the IP Only detection engine context
911
 *
912
 * \param de_ctx Pointer to the current detection engine
913
 * \param io_ctx Pointer to the current ip only detection engine
914
 */
915
void IPOnlyInit(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx)
916
{
7✔
917
    io_ctx->tree_ipv4src = SCRadix4TreeInitialize();
7✔
918
    io_ctx->tree_ipv4dst = SCRadix4TreeInitialize();
7✔
919
    io_ctx->tree_ipv6src = SCRadix6TreeInitialize();
7✔
920
    io_ctx->tree_ipv6dst = SCRadix6TreeInitialize();
7✔
921

922
    io_ctx->sig_mapping = SCCalloc(1, de_ctx->sig_array_len * sizeof(uint32_t));
7✔
923
    if (io_ctx->sig_mapping == NULL) {
7✔
924
        FatalError("Unable to allocate iponly signature tracking area");
×
925
    }
×
926
    io_ctx->sig_mapping_size = 0;
7✔
927
}
7✔
928

929
SigIntId IPOnlyTrackSigNum(DetectEngineIPOnlyCtx *io_ctx, SigIntId signum)
930
{
×
931
    SigIntId loc = io_ctx->sig_mapping_size;
×
932
    io_ctx->sig_mapping[loc] = signum;
×
933
    io_ctx->sig_mapping_size++;
×
934
    return loc;
×
935
}
×
936

937
/**
938
 * \brief Print stats of the IP Only engine
939
 *
940
 * \param de_ctx Pointer to the current detection engine
941
 * \param io_ctx Pointer to the current ip only detection engine
942
 */
943
void IPOnlyPrint(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx)
944
{
7✔
945
    /* XXX: how are we going to print the stats now? */
946
}
7✔
947

948
/**
949
 * \brief Deinitialize the IP Only detection engine context
950
 *
951
 * \param de_ctx Pointer to the current detection engine
952
 * \param io_ctx Pointer to the current ip only detection engine
953
 */
954
void IPOnlyDeinit(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx)
955
{
7✔
956

957
    if (io_ctx == NULL)
7✔
958
        return;
×
959

960
    SCRadix4TreeRelease(&io_ctx->tree_ipv4src, &iponly_radix4_config);
7✔
961
    SCRadix4TreeRelease(&io_ctx->tree_ipv4dst, &iponly_radix4_config);
7✔
962

963
    SCRadix6TreeRelease(&io_ctx->tree_ipv6src, &iponly_radix6_config);
7✔
964
    SCRadix6TreeRelease(&io_ctx->tree_ipv6dst, &iponly_radix6_config);
7✔
965

966
    if (io_ctx->sig_mapping != NULL)
7✔
967
        SCFree(io_ctx->sig_mapping);
7✔
968
    io_ctx->sig_mapping = NULL;
7✔
969
}
7✔
970

971
static inline int IPOnlyMatchCompatSMs(
972
        ThreadVars *tv, DetectEngineThreadCtx *det_ctx, const Signature *s, Packet *p)
973
{
×
974
    KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_MATCH);
×
975
    const SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_MATCH];
×
976
    while (smd) {
×
977
        DEBUG_VALIDATE_BUG_ON(!(sigmatch_table[smd->type].flags & SIGMATCH_IPONLY_COMPAT));
×
978
        KEYWORD_PROFILING_START;
×
979
        if (sigmatch_table[smd->type].Match(det_ctx, p, s, smd->ctx) > 0) {
×
980
            KEYWORD_PROFILING_END(det_ctx, smd->type, 1);
×
981
            if (smd->is_last)
×
982
                break;
×
983
            smd++;
×
984
            continue;
×
985
        }
×
986
        KEYWORD_PROFILING_END(det_ctx, smd->type, 0);
×
987
        return 0;
×
988
    }
×
989
    return 1;
×
990
}
×
991

992
/**
993
 * \brief Match a packet against the IP Only detection engine contexts
994
 *
995
 * \param de_ctx Pointer to the current detection engine
996
 * \param io_ctx Pointer to the current ip only detection engine
997
 * \param io_ctx Pointer to the current ip only thread detection engine
998
 * \param p Pointer to the Packet to match against
999
 */
1000
void IPOnlyMatchPacket(ThreadVars *tv, const DetectEngineCtx *de_ctx,
1001
        DetectEngineThreadCtx *det_ctx, const DetectEngineIPOnlyCtx *io_ctx, Packet *p)
1002
{
88,535✔
1003
    SigNumArray *src = NULL;
88,535✔
1004
    SigNumArray *dst = NULL;
88,535✔
1005
    void *user_data_src = NULL, *user_data_dst = NULL;
88,535✔
1006

1007
    SCEnter();
88,535✔
1008

1009
    if (p->src.family == AF_INET) {
88,535✔
1010
        (void)SCRadix4TreeFindBestMatch(
28,771✔
1011
                &io_ctx->tree_ipv4src, (uint8_t *)&GET_IPV4_SRC_ADDR_U32(p), &user_data_src);
28,771✔
1012
    } else if (p->src.family == AF_INET6) {
78,436✔
1013
        (void)SCRadix6TreeFindBestMatch(
58,463✔
1014
                &io_ctx->tree_ipv6src, (uint8_t *)&GET_IPV6_SRC_ADDR(p), &user_data_src);
58,463✔
1015
    }
58,463✔
1016

1017
    if (p->dst.family == AF_INET) {
88,535✔
1018
        (void)SCRadix4TreeFindBestMatch(
28,770✔
1019
                &io_ctx->tree_ipv4dst, (uint8_t *)&GET_IPV4_DST_ADDR_U32(p), &user_data_dst);
28,770✔
1020
    } else if (p->dst.family == AF_INET6) {
78,437✔
1021
        (void)SCRadix6TreeFindBestMatch(
58,421✔
1022
                &io_ctx->tree_ipv6dst, (uint8_t *)&GET_IPV6_DST_ADDR(p), &user_data_dst);
58,421✔
1023
    }
58,421✔
1024

1025
    src = user_data_src;
88,535✔
1026
    dst = user_data_dst;
88,535✔
1027

1028
    if (src == NULL || dst == NULL)
88,535✔
1029
        SCReturn;
88,525✔
1030

1031
    for (uint32_t u = 0; u < src->size; u++) {
10✔
1032
        SCLogDebug("And %"PRIu8" & %"PRIu8, src->array[u], dst->array[u]);
×
1033

1034
        uint8_t bitarray = dst->array[u] & src->array[u];
×
1035

1036
        /* We have to move the logic of the signature checking
1037
         * to the main detect loop, in order to apply the
1038
         * priority of actions (pass, drop, reject, alert) */
1039
        if (!bitarray)
×
1040
            continue;
×
1041

1042
        /* We have a match :) Let's see from which signum's */
1043

1044
        for (uint8_t i = 0; i < 8; i++, bitarray = bitarray >> 1) {
×
1045
            if (bitarray & 0x01) {
×
1046
                const Signature *s = de_ctx->sig_array[io_ctx->sig_mapping[u * 8 + i]];
×
1047

1048
                if ((s->proto.flags & DETECT_PROTO_IPV4) && !PacketIsIPv4(p)) {
×
1049
                    SCLogDebug("ip version didn't match");
×
1050
                    continue;
×
1051
                }
×
1052
                if ((s->proto.flags & DETECT_PROTO_IPV6) && !PacketIsIPv6(p)) {
×
1053
                    SCLogDebug("ip version didn't match");
×
1054
                    continue;
×
1055
                }
×
1056
                if (DetectProtoContainsProto(&s->proto, PacketGetIPProto(p)) == 0) {
×
1057
                    SCLogDebug("proto didn't match");
×
1058
                    continue;
×
1059
                }
×
1060

1061
                /* check the source & dst port in the sig */
1062
                if (p->proto == IPPROTO_TCP || p->proto == IPPROTO_UDP ||
×
1063
                        p->proto == IPPROTO_SCTP) {
×
1064
                    if (!(s->flags & SIG_FLAG_DP_ANY)) {
×
1065
                        if (p->flags & PKT_IS_FRAGMENT)
×
1066
                            continue;
×
1067

1068
                        const DetectPort *dport = DetectPortLookupGroup(s->dp, p->dp);
×
1069
                        if (dport == NULL) {
×
1070
                            SCLogDebug("dport didn't match.");
×
1071
                            continue;
×
1072
                        }
×
1073
                    }
×
1074
                    if (!(s->flags & SIG_FLAG_SP_ANY)) {
×
1075
                        if (p->flags & PKT_IS_FRAGMENT)
×
1076
                            continue;
×
1077

1078
                        const DetectPort *sport = DetectPortLookupGroup(s->sp, p->sp);
×
1079
                        if (sport == NULL) {
×
1080
                            SCLogDebug("sport didn't match.");
×
1081
                            continue;
×
1082
                        }
×
1083
                    }
×
1084
                } else if ((s->flags & (SIG_FLAG_DP_ANY | SIG_FLAG_SP_ANY)) !=
×
1085
                           (SIG_FLAG_DP_ANY | SIG_FLAG_SP_ANY)) {
×
1086
                    SCLogDebug("port-less protocol and sig needs ports");
×
1087
                    continue;
×
1088
                }
×
1089

1090
                if (!IPOnlyMatchCompatSMs(tv, det_ctx, s, p)) {
×
1091
                    continue;
×
1092
                }
×
1093

1094
                SCLogDebug("Signum %" PRIu32 " match (sid: %" PRIu32 ", msg: %s)", u * 8 + i, s->id,
×
1095
                        s->msg);
×
1096

1097
                if (s->sm_arrays[DETECT_SM_LIST_POSTMATCH] != NULL) {
×
1098
                    KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_POSTMATCH);
×
1099
                    const SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_POSTMATCH];
×
1100

1101
                    SCLogDebug("running match functions, sm %p", smd);
×
1102

1103
                    if (smd != NULL) {
×
1104
                        while (1) {
×
1105
                            KEYWORD_PROFILING_START;
×
1106
                            (void)sigmatch_table[smd->type].Match(det_ctx, p, s, smd->ctx);
×
1107
                            KEYWORD_PROFILING_END(det_ctx, smd->type, 1);
×
1108
                            if (smd->is_last)
×
1109
                                break;
×
1110
                            smd++;
×
1111
                        }
×
1112
                    }
×
1113
                }
×
1114
                AlertQueueAppend(det_ctx, s, p, 0, 0);
×
1115
            }
×
1116
        }
×
1117
    }
×
1118
    SCReturn;
10✔
1119
}
88,535✔
1120

1121
static void IPOnlyPrepareUpdateBitarray(const IPOnlyCIDRItem *src, SigNumArray *sna)
1122
{
×
1123
    uint8_t tmp = (uint8_t)(1 << (src->signum % 8));
×
1124
    if (src->negated > 0)
×
1125
        /* Unset it */
1126
        sna->array[src->signum / 8] &= ~tmp;
×
1127
    else
×
1128
        /* Set it */
1129
        sna->array[src->signum / 8] |= tmp;
×
1130
}
×
1131

1132
/**
1133
 * \brief Build the radix trees from the lists of parsed addresses in CIDR format
1134
 *        the result should be 4 radix trees: src/dst ipv4 and src/dst ipv6
1135
 *        holding SigNumArrays, each of them with a hierarchical relation
1136
 *        of subnets and hosts
1137
 *
1138
 * \param de_ctx Pointer to the current detection engine
1139
 */
1140
void IPOnlyPrepare(DetectEngineCtx *de_ctx)
1141
{
7✔
1142
    SCLogDebug("Preparing Final Lists");
7✔
1143

1144
    /*
1145
       IPOnlyCIDRListPrint((de_ctx->io_ctx).ip_src);
1146
       IPOnlyCIDRListPrint((de_ctx->io_ctx).ip_dst);
1147
     */
1148

1149
    IPOnlyCIDRListQSort(&de_ctx->io_ctx.ip_src);
7✔
1150
    IPOnlyCIDRListQSort(&de_ctx->io_ctx.ip_dst);
7✔
1151

1152
    SCRadix4Node *node4 = NULL;
7✔
1153
    SCRadix6Node *node6 = NULL;
7✔
1154

1155
    /* Prepare Src radix trees */
1156
    for (IPOnlyCIDRItem *src = de_ctx->io_ctx.ip_src; src != NULL;) {
7✔
1157
        if (src->family == AF_INET) {
×
1158
        /*
1159
            SCLogDebug("To IPv4");
1160
            SCLogDebug("Item has netmask %"PRIu16" negated: %s; IP: %s; "
1161
                       "signum: %"PRIu16, src->netmask,
1162
                        (src->negated) ? "yes":"no",
1163
                        inet_ntoa( *(struct in_addr*)&src->ip[0]),
1164
                        src->signum);
1165
        */
1166

1167
            void *user_data = NULL;
×
1168
            if (src->netmask == 32)
×
1169
                (void)SCRadix4TreeFindExactMatch(
×
1170
                        &de_ctx->io_ctx.tree_ipv4src, (uint8_t *)&src->ip[0], &user_data);
×
1171
            else
×
1172
                (void)SCRadix4TreeFindNetblock(&de_ctx->io_ctx.tree_ipv4src, (uint8_t *)&src->ip[0],
×
1173
                        src->netmask, &user_data);
×
1174
            if (user_data == NULL) {
×
1175
                SCLogDebug("Exact match not found");
×
1176

1177
                /** Not found, look if there's a subnet of this range with
1178
                 * bigger netmask */
1179
                (void)SCRadix4TreeFindBestMatch(
×
1180
                        &de_ctx->io_ctx.tree_ipv4src, (uint8_t *)&src->ip[0], &user_data);
×
1181
                if (user_data == NULL) {
×
1182
                    SCLogDebug("best match not found");
×
1183

1184
                    /* Not found, insert a new one */
1185
                    SigNumArray *sna = SigNumArrayNew(de_ctx, &de_ctx->io_ctx);
×
1186
                    IPOnlyPrepareUpdateBitarray(src, sna);
×
1187

1188
                    if (src->netmask == 32)
×
1189
                        node4 = SCRadix4AddKeyIPV4(&de_ctx->io_ctx.tree_ipv4src,
×
1190
                                &iponly_radix4_config, (uint8_t *)&src->ip[0], sna);
×
1191
                    else
×
1192
                        node4 = SCRadix4AddKeyIPV4Netblock(&de_ctx->io_ctx.tree_ipv4src,
×
1193
                                &iponly_radix4_config, (uint8_t *)&src->ip[0], src->netmask, sna);
×
1194
                    if (node4 == NULL)
×
1195
                        SCLogError("Error inserting in the "
×
1196
                                   "src ipv4 radix tree");
×
1197
                } else {
×
1198
                    SCLogDebug("Best match found");
×
1199

1200
                    /* Found, copy the sig num table, add this signum and insert */
1201
                    SigNumArray *sna = SigNumArrayCopy((SigNumArray *)user_data);
×
1202
                    IPOnlyPrepareUpdateBitarray(src, sna);
×
1203

1204
                    if (src->netmask == 32)
×
1205
                        node4 = SCRadix4AddKeyIPV4(&de_ctx->io_ctx.tree_ipv4src,
×
1206
                                &iponly_radix4_config, (uint8_t *)&src->ip[0], sna);
×
1207
                    else
×
1208
                        node4 = SCRadix4AddKeyIPV4Netblock(&de_ctx->io_ctx.tree_ipv4src,
×
1209
                                &iponly_radix4_config, (uint8_t *)&src->ip[0], src->netmask, sna);
×
1210
                    if (node4 == NULL) {
×
1211
                        char tmpstr[64];
×
1212
                        PrintInet(src->family, &src->ip[0], tmpstr, sizeof(tmpstr));
×
1213
                        SCLogError("Error inserting in the"
×
1214
                                   " src ipv4 radix tree ip %s netmask %" PRIu8,
×
1215
                                tmpstr, src->netmask);
×
1216
                        exit(-1);
×
1217
                    }
×
1218
                }
×
1219
            } else {
×
1220
                SCLogDebug("Exact match found");
×
1221

1222
                /* it's already inserted. Update it */
1223
                SigNumArray *sna = (SigNumArray *)user_data;
×
1224
                IPOnlyPrepareUpdateBitarray(src, sna);
×
1225
            }
×
1226
        } else if (src->family == AF_INET6) {
×
1227
            SCLogDebug("To IPv6");
×
1228

1229
            void *user_data = NULL;
×
1230
            if (src->netmask == 128)
×
1231
                (void)SCRadix6TreeFindExactMatch(
×
1232
                        &de_ctx->io_ctx.tree_ipv6src, (uint8_t *)&src->ip[0], &user_data);
×
1233
            else
×
1234
                (void)SCRadix6TreeFindNetblock(&de_ctx->io_ctx.tree_ipv6src, (uint8_t *)&src->ip[0],
×
1235
                        src->netmask, &user_data);
×
1236
            if (user_data == NULL) {
×
1237
                /* Not found, look if there's a subnet of this range with bigger netmask */
1238
                (void)SCRadix6TreeFindBestMatch(
×
1239
                        &de_ctx->io_ctx.tree_ipv6src, (uint8_t *)&src->ip[0], &user_data);
×
1240
                if (user_data == NULL) {
×
1241
                    /* Not found, insert a new one */
1242
                    SigNumArray *sna = SigNumArrayNew(de_ctx, &de_ctx->io_ctx);
×
1243
                    IPOnlyPrepareUpdateBitarray(src, sna);
×
1244

1245
                    if (src->netmask == 128)
×
1246
                        node6 = SCRadix6AddKeyIPV6(&de_ctx->io_ctx.tree_ipv6src,
×
1247
                                &iponly_radix6_config, (uint8_t *)&src->ip[0], sna);
×
1248
                    else
×
1249
                        node6 = SCRadix6AddKeyIPV6Netblock(&de_ctx->io_ctx.tree_ipv6src,
×
1250
                                &iponly_radix6_config, (uint8_t *)&src->ip[0], src->netmask, sna);
×
1251
                    if (node6 == NULL)
×
1252
                        SCLogError("Error inserting in the src "
×
1253
                                   "ipv6 radix tree");
×
1254
                } else {
×
1255
                    /* Found, copy the sig num table, add this signum and insert */
1256
                    SigNumArray *sna = SigNumArrayCopy((SigNumArray *)user_data);
×
1257
                    IPOnlyPrepareUpdateBitarray(src, sna);
×
1258

1259
                    if (src->netmask == 128)
×
1260
                        node6 = SCRadix6AddKeyIPV6(&de_ctx->io_ctx.tree_ipv6src,
×
1261
                                &iponly_radix6_config, (uint8_t *)&src->ip[0], sna);
×
1262
                    else
×
1263
                        node6 = SCRadix6AddKeyIPV6Netblock(&de_ctx->io_ctx.tree_ipv6src,
×
1264
                                &iponly_radix6_config, (uint8_t *)&src->ip[0], src->netmask, sna);
×
1265
                    if (node6 == NULL)
×
1266
                        SCLogError("Error inserting in the src "
×
1267
                                   "ipv6 radix tree");
×
1268
                }
×
1269
            } else {
×
1270
                /* it's already inserted. Update it */
1271
                SigNumArray *sna = (SigNumArray *)user_data;
×
1272
                IPOnlyPrepareUpdateBitarray(src, sna);
×
1273
            }
×
1274
        }
×
1275
        IPOnlyCIDRItem *tmpaux = src;
×
1276
        src = src->next;
×
1277
        SCFree(tmpaux);
×
1278
    }
×
1279

1280
    SCLogDebug("dsts:");
7✔
1281

1282
    /* Prepare Dst radix trees */
1283
    for (IPOnlyCIDRItem *dst = de_ctx->io_ctx.ip_dst; dst != NULL;) {
7✔
1284
        if (dst->family == AF_INET) {
×
1285
            SCLogDebug("To IPv4");
×
1286
            SCLogDebug("Item has netmask %"PRIu8" negated: %s; IP: %s; signum:"
×
1287
                       " %"PRIu32"", dst->netmask, (dst->negated)?"yes":"no",
×
1288
                       inet_ntoa(*(struct in_addr*)&dst->ip[0]), dst->signum);
×
1289

1290
            void *user_data = NULL;
×
1291
            if (dst->netmask == 32)
×
1292
                (void)SCRadix4TreeFindExactMatch(
×
1293
                        &de_ctx->io_ctx.tree_ipv4dst, (uint8_t *)&dst->ip[0], &user_data);
×
1294
            else
×
1295
                (void)SCRadix4TreeFindNetblock(&de_ctx->io_ctx.tree_ipv4dst, (uint8_t *)&dst->ip[0],
×
1296
                        dst->netmask, &user_data);
×
1297
            if (user_data == NULL) {
×
1298
                SCLogDebug("Exact match not found");
×
1299

1300
                /**
1301
                 * Not found, look if there's a subnet of this range
1302
                 * with bigger netmask
1303
                 */
1304
                (void)SCRadix4TreeFindBestMatch(
×
1305
                        &de_ctx->io_ctx.tree_ipv4dst, (uint8_t *)&dst->ip[0], &user_data);
×
1306
                if (user_data == NULL) {
×
1307
                    SCLogDebug("Best match not found");
×
1308

1309
                    /** Not found, insert a new one */
1310
                    SigNumArray *sna = SigNumArrayNew(de_ctx, &de_ctx->io_ctx);
×
1311
                    IPOnlyPrepareUpdateBitarray(dst, sna);
×
1312

1313
                    if (dst->netmask == 32)
×
1314
                        node4 = SCRadix4AddKeyIPV4(&de_ctx->io_ctx.tree_ipv4dst,
×
1315
                                &iponly_radix4_config, (uint8_t *)&dst->ip[0], sna);
×
1316
                    else
×
1317
                        node4 = SCRadix4AddKeyIPV4Netblock(&de_ctx->io_ctx.tree_ipv4dst,
×
1318
                                &iponly_radix4_config, (uint8_t *)&dst->ip[0], dst->netmask, sna);
×
1319
                    if (node4 == NULL)
×
1320
                        SCLogError("Error inserting in the dst "
×
1321
                                   "ipv4 radix tree");
×
1322
                } else {
×
1323
                    SCLogDebug("Best match found");
×
1324

1325
                    /* Found, copy the sig num table, add this signum and insert */
1326
                    SigNumArray *sna = SigNumArrayCopy((SigNumArray *)user_data);
×
1327
                    IPOnlyPrepareUpdateBitarray(dst, sna);
×
1328

1329
                    if (dst->netmask == 32)
×
1330
                        node4 = SCRadix4AddKeyIPV4(&de_ctx->io_ctx.tree_ipv4dst,
×
1331
                                &iponly_radix4_config, (uint8_t *)&dst->ip[0], sna);
×
1332
                    else
×
1333
                        node4 = SCRadix4AddKeyIPV4Netblock(&de_ctx->io_ctx.tree_ipv4dst,
×
1334
                                &iponly_radix4_config, (uint8_t *)&dst->ip[0], dst->netmask, sna);
×
1335

1336
                    if (node4 == NULL)
×
1337
                        SCLogError("Error inserting in the dst "
×
1338
                                   "ipv4 radix tree");
×
1339
                }
×
1340
            } else {
×
1341
                SCLogDebug("Exact match found");
×
1342

1343
                /* it's already inserted. Update it */
1344
                SigNumArray *sna = (SigNumArray *)user_data;
×
1345
                IPOnlyPrepareUpdateBitarray(dst, sna);
×
1346
            }
×
1347
        } else if (dst->family == AF_INET6) {
×
1348
            SCLogDebug("To IPv6");
×
1349

1350
            void *user_data = NULL;
×
1351
            if (dst->netmask == 128)
×
1352
                (void)SCRadix6TreeFindExactMatch(
×
1353
                        &de_ctx->io_ctx.tree_ipv6dst, (uint8_t *)&dst->ip[0], &user_data);
×
1354
            else
×
1355
                (void)SCRadix6TreeFindNetblock(&de_ctx->io_ctx.tree_ipv6dst, (uint8_t *)&dst->ip[0],
×
1356
                        dst->netmask, &user_data);
×
1357
            if (user_data == NULL) {
×
1358
                /** Not found, look if there's a subnet of this range with
1359
                 * bigger netmask
1360
                 */
1361
                (void)SCRadix6TreeFindBestMatch(
×
1362
                        &de_ctx->io_ctx.tree_ipv6dst, (uint8_t *)&dst->ip[0], &user_data);
×
1363
                if (user_data == NULL) {
×
1364
                    /* Not found, insert a new one */
1365
                    SigNumArray *sna = SigNumArrayNew(de_ctx, &de_ctx->io_ctx);
×
1366
                    IPOnlyPrepareUpdateBitarray(dst, sna);
×
1367

1368
                    if (dst->netmask == 128)
×
1369
                        node6 = SCRadix6AddKeyIPV6(&de_ctx->io_ctx.tree_ipv6dst,
×
1370
                                &iponly_radix6_config, (uint8_t *)&dst->ip[0], sna);
×
1371
                    else
×
1372
                        node6 = SCRadix6AddKeyIPV6Netblock(&de_ctx->io_ctx.tree_ipv6dst,
×
1373
                                &iponly_radix6_config, (uint8_t *)&dst->ip[0], dst->netmask, sna);
×
1374
                    if (node6 == NULL)
×
1375
                        SCLogError("Error inserting in the dst "
×
1376
                                   "ipv6 radix tree");
×
1377
                } else {
×
1378
                    /* Found, copy the sig num table, add this signum and insert */
1379
                    SigNumArray *sna = SigNumArrayCopy((SigNumArray *)user_data);
×
1380
                    IPOnlyPrepareUpdateBitarray(dst, sna);
×
1381

1382
                    if (dst->netmask == 128)
×
1383
                        node6 = SCRadix6AddKeyIPV6(&de_ctx->io_ctx.tree_ipv6dst,
×
1384
                                &iponly_radix6_config, (uint8_t *)&dst->ip[0], sna);
×
1385
                    else
×
1386
                        node6 = SCRadix6AddKeyIPV6Netblock(&de_ctx->io_ctx.tree_ipv6dst,
×
1387
                                &iponly_radix6_config, (uint8_t *)&dst->ip[0], dst->netmask, sna);
×
1388
                    if (node6 == NULL)
×
1389
                        SCLogError("Error inserting in the dst "
×
1390
                                   "ipv6 radix tree");
×
1391
                }
×
1392
            } else {
×
1393
                /* it's already inserted. Update it */
1394
                SigNumArray *sna = (SigNumArray *)user_data;
×
1395
                IPOnlyPrepareUpdateBitarray(dst, sna);
×
1396
            }
×
1397
        }
×
1398
        IPOnlyCIDRItem *tmpaux = dst;
×
1399
        dst = dst->next;
×
1400
        SCFree(tmpaux);
×
1401
    }
×
1402
}
7✔
1403

1404
/**
1405
 * \brief Add a signature to the lists of Addresses in CIDR format (sorted)
1406
 *        this step is necessary to build the radix tree with a hierarchical
1407
 *        relation between nodes
1408
 * \param de_ctx Pointer to the current detection engine context
1409
 * \param de_ctx Pointer to the current ip only detection engine contest
1410
 * \param s Pointer to the current signature
1411
 */
1412
void IPOnlyAddSignature(DetectEngineCtx *de_ctx, DetectEngineIPOnlyCtx *io_ctx,
1413
                        Signature *s)
1414
{
×
1415
    if (!(s->type == SIG_TYPE_IPONLY))
×
1416
        return;
×
1417

1418
    SigIntId mapped_signum = IPOnlyTrackSigNum(io_ctx, s->iid);
×
1419
    SCLogDebug("Adding IPs from rule: %" PRIu32 " (%s) as %" PRIu32 " mapped to %" PRIu32 "\n",
×
1420
            s->id, s->msg, s->iid, mapped_signum);
×
1421
    /* Set the internal signum to the list before merging */
1422
    IPOnlyCIDRListSetSigNum(s->init_data->cidr_src, mapped_signum);
×
1423

1424
    IPOnlyCIDRListSetSigNum(s->init_data->cidr_dst, mapped_signum);
×
1425

1426
    /**
1427
     * ipv4 and ipv6 are mixed, but later we will separate them into
1428
     * different trees
1429
     */
1430
    io_ctx->ip_src = IPOnlyCIDRItemInsert(io_ctx->ip_src, s->init_data->cidr_src);
×
1431
    io_ctx->ip_dst = IPOnlyCIDRItemInsert(io_ctx->ip_dst, s->init_data->cidr_dst);
×
1432

1433
    if (mapped_signum > io_ctx->max_idx)
×
1434
        io_ctx->max_idx = mapped_signum;
×
1435

1436
    /** no longer ref to this, it's in the table now */
1437
    s->init_data->cidr_src = NULL;
×
1438
    s->init_data->cidr_dst = NULL;
×
1439
}
×
1440

1441
#ifdef UNITTESTS
1442
/**
1443
 * \test check that we set a Signature as IPOnly because it has no rule
1444
 *       option appending a SigMatch and no port is fixed
1445
 */
1446

1447
static int IPOnlyTestSig01(void)
1448
{
1449
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1450
    FAIL_IF(de_ctx == NULL);
1451
    de_ctx->flags |= DE_QUIET;
1452

1453
    Signature *s = SigInit(de_ctx,"alert tcp any any -> any any (sid:400001; rev:1;)");
1454
    FAIL_IF(s == NULL);
1455

1456
    FAIL_IF(SignatureIsIPOnly(de_ctx, s) == 0);
1457
    SigFree(de_ctx, s);
1458
    DetectEngineCtxFree(de_ctx);
1459
    PASS;
1460
}
1461

1462
/**
1463
 * \test check that we don't set a Signature as IPOnly because it has no rule
1464
 *       option appending a SigMatch but a port is fixed
1465
 */
1466

1467
static int IPOnlyTestSig02 (void)
1468
{
1469
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
1470
    FAIL_IF(de_ctx == NULL);
1471
    de_ctx->flags |= DE_QUIET;
1472

1473
    Signature *s = SigInit(de_ctx,"alert tcp any any -> any 80 (sid:400001; rev:1;)");
1474
    FAIL_IF(s == NULL);
1475

1476
    FAIL_IF(SignatureIsIPOnly(de_ctx, s) == 0);
1477
    SigFree(de_ctx, s);
1478
    DetectEngineCtxFree(de_ctx);
1479
    PASS;
1480
}
1481

1482
/**
1483
 * \test check that we set don't set a Signature as IPOnly
1484
 *  because it has rule options appending a SigMatch like content, and pcre
1485
 */
1486

1487
static int IPOnlyTestSig03 (void)
1488
{
1489
    int result = 1;
1490
    DetectEngineCtx *de_ctx;
1491
    Signature *s=NULL;
1492

1493
    de_ctx = DetectEngineCtxInit();
1494
    if (de_ctx == NULL)
1495
        goto end;
1496
    de_ctx->flags |= DE_QUIET;
1497

1498
    /* combination of pcre and content */
1499
    s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (pcre and content) \"; content:\"php\"; pcre:\"/require(_once)?/i\"; classtype:misc-activity; sid:400001; rev:1;)");
1500
    if (s == NULL) {
1501
        goto end;
1502
    }
1503
    if(SignatureIsIPOnly(de_ctx, s))
1504
    {
1505
        printf("got a IPOnly signature (content): ");
1506
        result=0;
1507
    }
1508
    SigFree(de_ctx, s);
1509

1510
    /* content */
1511
    s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (content) \"; content:\"match something\"; classtype:misc-activity; sid:400001; rev:1;)");
1512
    if (s == NULL) {
1513
        goto end;
1514
    }
1515
    if(SignatureIsIPOnly(de_ctx, s))
1516
    {
1517
        printf("got a IPOnly signature (content): ");
1518
        result=0;
1519
    }
1520
    SigFree(de_ctx, s);
1521

1522
    /* uricontent */
1523
    s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (uricontent) \"; uricontent:\"match something\"; classtype:misc-activity; sid:400001; rev:1;)");
1524
    if (s == NULL) {
1525
        goto end;
1526
    }
1527
    if(SignatureIsIPOnly(de_ctx, s))
1528
    {
1529
        printf("got a IPOnly signature (uricontent): ");
1530
        result=0;
1531
    }
1532
    SigFree(de_ctx, s);
1533

1534
    /* pcre */
1535
    s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (pcre) \"; pcre:\"/e?idps rule[sz]/i\"; classtype:misc-activity; sid:400001; rev:1;)");
1536
    if (s == NULL) {
1537
        goto end;
1538
    }
1539
    if(SignatureIsIPOnly(de_ctx, s))
1540
    {
1541
        printf("got a IPOnly signature (pcre): ");
1542
        result=0;
1543
    }
1544
    SigFree(de_ctx, s);
1545

1546
    /* flow */
1547
    s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (flow) \"; flow:to_server; classtype:misc-activity; sid:400001; rev:1;)");
1548
    if (s == NULL) {
1549
        goto end;
1550
    }
1551
    if(SignatureIsIPOnly(de_ctx, s))
1552
    {
1553
        printf("got a IPOnly signature (flow): ");
1554
        result=0;
1555
    }
1556
    SigFree(de_ctx, s);
1557

1558
    /* dsize */
1559
    s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (dsize) \"; dsize:100; classtype:misc-activity; sid:400001; rev:1;)");
1560
    if (s == NULL) {
1561
        goto end;
1562
    }
1563
    if(SignatureIsIPOnly(de_ctx, s))
1564
    {
1565
        printf("got a IPOnly signature (dsize): ");
1566
        result=0;
1567
    }
1568
    SigFree(de_ctx, s);
1569

1570
    /* flowbits */
1571
    s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (flowbits) \"; flowbits:unset; classtype:misc-activity; sid:400001; rev:1;)");
1572
    if (s == NULL) {
1573
        goto end;
1574
    }
1575
    if(SignatureIsIPOnly(de_ctx, s))
1576
    {
1577
        printf("got a IPOnly signature (flowbits): ");
1578
        result=0;
1579
    }
1580
    SigFree(de_ctx, s);
1581

1582
    /* flowvar */
1583
    s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (flowvar) \"; pcre:\"/(?<flow_var>.*)/i\"; flowvar:var,\"str\"; classtype:misc-activity; sid:400001; rev:1;)");
1584
    if (s == NULL) {
1585
        goto end;
1586
    }
1587
    if(SignatureIsIPOnly(de_ctx, s))
1588
    {
1589
        printf("got a IPOnly signature (flowvar): ");
1590
        result=0;
1591
    }
1592
    SigFree(de_ctx, s);
1593

1594
    /* pktvar */
1595
    s = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"SigTest40-03 sig is not IPOnly (pktvar) \"; pcre:\"/(?<pkt_var>.*)/i\"; pktvar:var,\"str\"; classtype:misc-activity; sid:400001; rev:1;)");
1596
    if (s == NULL) {
1597
        goto end;
1598
    }
1599
    if(SignatureIsIPOnly(de_ctx, s))
1600
    {
1601
        printf("got a IPOnly signature (pktvar): ");
1602
        result=0;
1603
    }
1604
    SigFree(de_ctx, s);
1605

1606
end:
1607
    if (de_ctx != NULL)
1608
        DetectEngineCtxFree(de_ctx);
1609
    return result;
1610
}
1611

1612
/**
1613
 * \test
1614
 */
1615
static int IPOnlyTestSig04 (void)
1616
{
1617
    int result = 1;
1618
    IPOnlyCIDRItem *head = NULL;
1619

1620
    // Test a linked list of size 0, 1, 2, ..., 5
1621
    for (int size = 0; size < 6; size++) {
1622
        IPOnlyCIDRItem *new = NULL;
1623

1624
        if (size > 0) {
1625
            new = IPOnlyCIDRItemNew();
1626
            new->netmask = 10;
1627
            new->ip[0] = 3;
1628

1629
            head = IPOnlyCIDRItemInsert(head, new);
1630
        }
1631

1632
        if (size > 1) {
1633
            new = IPOnlyCIDRItemNew();
1634
            new->netmask = 11;
1635

1636
            head = IPOnlyCIDRItemInsert(head, new);
1637
        }
1638

1639
        if (size > 2) {
1640
            new = IPOnlyCIDRItemNew();
1641
            new->netmask = 9;
1642

1643
            head = IPOnlyCIDRItemInsert(head, new);
1644
        }
1645

1646
        if (size > 3) {
1647
            new = IPOnlyCIDRItemNew();
1648
            new->netmask = 10;
1649
            new->ip[0] = 1;
1650

1651
            head = IPOnlyCIDRItemInsert(head, new);
1652
        }
1653

1654
        if (size > 4) {
1655
            new = IPOnlyCIDRItemNew();
1656
            new->netmask = 10;
1657
            new->ip[0] = 2;
1658

1659
            head = IPOnlyCIDRItemInsert(head, new);
1660
        }
1661

1662
        IPOnlyCIDRListPrint(head);
1663

1664
        IPOnlyCIDRListQSort(&head);
1665

1666
        if (size == 0) {
1667
            if (head != NULL) {
1668
                result = 0;
1669
                goto end;
1670
            }
1671
        }
1672

1673
        /**
1674
         * Validate the following list entries for each size
1675
         * 1 - 10
1676
         * 2 - 10<3> 11
1677
         * 3 - 9     10<3> 11
1678
         * 4 - 9     10<1> 10<3> 11
1679
         * 5 - 9     10<1> 10<2> 10<3> 11
1680
         */
1681
        new = head;
1682
        if (size >= 3) {
1683
            if (new->netmask != 9) {
1684
                result = 0;
1685
                goto end;
1686
            }
1687
            new = new->next;
1688
        }
1689

1690
        if (size >= 4) {
1691
            if (new->netmask != 10 || new->ip[0] != 1) {
1692
                result = 0;
1693
                goto end;
1694
            }
1695
            new = new->next;
1696
        }
1697

1698
        if (size >= 5) {
1699
            if (new->netmask != 10 || new->ip[0] != 2) {
1700
                result = 0;
1701
                goto end;
1702
            }
1703
            new = new->next;
1704
        }
1705

1706
        if (size >= 1) {
1707
            if (new->netmask != 10 || new->ip[0] != 3) {
1708
                result = 0;
1709
                goto end;
1710
            }
1711
            new = new->next;
1712
        }
1713

1714
        if (size >= 2) {
1715
            if (new->netmask != 11) {
1716
                result = 0;
1717
                goto end;
1718
            }
1719
            new = new->next;
1720
        }
1721

1722
        if (new != NULL) {
1723
            result = 0;
1724
            goto end;
1725
        }
1726

1727
        IPOnlyCIDRListFree(head);
1728
        head = NULL;
1729
    }
1730

1731
end:
1732
    if (head) {
1733
        IPOnlyCIDRListFree(head);
1734
        head = NULL;
1735
    }
1736
    return result;
1737
}
1738

1739
/**
1740
 * \test Test a set of ip only signatures making use a lot of
1741
 * addresses for src and dst (all should match)
1742
 */
1743
static int IPOnlyTestSig05(void)
1744
{
1745
    int result = 0;
1746
    uint8_t *buf = (uint8_t *)"Hi all!";
1747
    uint16_t buflen = strlen((char *)buf);
1748

1749
    uint8_t numpkts = 1;
1750
    uint8_t numsigs = 7;
1751

1752
    Packet *p[1];
1753

1754
    p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1755

1756
    const char *sigs[numsigs];
1757
    sigs[0]= "alert tcp 192.168.1.5 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)";
1758
    sigs[1]= "alert tcp any any -> 192.168.1.1 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)";
1759
    sigs[2]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)";
1760
    sigs[3]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)";
1761
    sigs[4]= "alert tcp 192.168.1.0/24 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)";
1762
    sigs[5]= "alert tcp any any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)";
1763
    sigs[6]= "alert tcp 192.168.1.0/24 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 7)\"; content:\"Hi all\";sid:7;)";
1764

1765
    /* Sid numbers (we could extract them from the sig) */
1766
    uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7};
1767
    uint32_t results[7] = { 1, 1, 1, 1, 1, 1, 1};
1768

1769
    result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
1770

1771
    UTHFreePackets(p, numpkts);
1772

1773
    return result;
1774
}
1775

1776
/**
1777
 * \test Test a set of ip only signatures making use a lot of
1778
 * addresses for src and dst (none should match)
1779
 */
1780
static int IPOnlyTestSig06(void)
1781
{
1782
    int result = 0;
1783
    uint8_t *buf = (uint8_t *)"Hi all!";
1784
    uint16_t buflen = strlen((char *)buf);
1785

1786
    uint8_t numpkts = 1;
1787
    uint8_t numsigs = 7;
1788

1789
    Packet *p[1];
1790

1791
    p[0] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "80.58.0.33", "195.235.113.3");
1792

1793
    const char *sigs[numsigs];
1794
    sigs[0]= "alert tcp 192.168.1.5 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)";
1795
    sigs[1]= "alert tcp any any -> 192.168.1.1 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)";
1796
    sigs[2]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)";
1797
    sigs[3]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)";
1798
    sigs[4]= "alert tcp 192.168.1.0/24 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)";
1799
    sigs[5]= "alert tcp any any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)";
1800
    sigs[6]= "alert tcp 192.168.1.0/24 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 7)\"; content:\"Hi all\";sid:7;)";
1801

1802
    /* Sid numbers (we could extract them from the sig) */
1803
    uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7};
1804
    uint32_t results[7] = { 0, 0, 0, 0, 0, 0, 0};
1805

1806
    result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
1807

1808
    UTHFreePackets(p, numpkts);
1809

1810
    return result;
1811
}
1812

1813
/* \todo fix it.  We have disabled this unittest because 599 exposes 608,
1814
 * which is why these unittests fail.  When we fix 608, we need to renable
1815
 * these sigs */
1816
#if 0
1817
/**
1818
 * \test Test a set of ip only signatures making use a lot of
1819
 * addresses for src and dst (all should match)
1820
 */
1821
static int IPOnlyTestSig07(void)
1822
{
1823
    int result = 0;
1824
    uint8_t *buf = (uint8_t *)"Hi all!";
1825
    uint16_t buflen = strlen((char *)buf);
1826

1827
    uint8_t numpkts = 1;
1828
    uint8_t numsigs = 7;
1829

1830
    Packet *p[1];
1831

1832
    p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
1833

1834
    char *sigs[numsigs];
1835
    sigs[0]= "alert tcp 192.168.1.5 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 1)\"; sid:1;)";
1836
    sigs[1]= "alert tcp [192.168.1.2,192.168.1.5,192.168.1.4] any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 2)\"; sid:2;)";
1837
    sigs[2]= "alert tcp [192.168.1.0/24,!192.168.1.1] any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)";
1838
    sigs[3]= "alert tcp [192.0.0.0/8,!192.168.0.0/16,192.168.1.0/24,!192.168.1.1] any -> [192.168.1.0/24,!192.168.1.5] any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)";
1839
    sigs[4]= "alert tcp any any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)";
1840
    sigs[5]= "alert tcp any any -> [192.168.0.0/16,!192.168.1.0/24,192.168.1.1] any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)";
1841
    sigs[6]= "alert tcp [78.129.202.0/24,192.168.1.5,78.129.205.64,78.129.214.103,78.129.223.19,78.129.233.17,78.137.168.33,78.140.132.11,78.140.133.15,78.140.138.105,78.140.139.105,78.140.141.107,78.140.141.114,78.140.143.103,78.140.143.13,78.140.145.144,78.140.170.164,78.140.23.18,78.143.16.7,78.143.46.124,78.157.129.71] any -> 192.168.1.1 any (msg:\"ET RBN Known Russian Business Network IP TCP - BLOCKING (246)\"; sid:7;)"; /* real sid:"2407490" */
1842

1843
    /* Sid numbers (we could extract them from the sig) */
1844
    uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7};
1845
    uint32_t results[7] = { 1, 1, 1, 1, 1, 1, 1};
1846

1847
    result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
1848

1849
    UTHFreePackets(p, numpkts);
1850

1851
    return result;
1852
}
1853
#endif
1854

1855
/**
1856
 * \test Test a set of ip only signatures making use a lot of
1857
 * addresses for src and dst (none should match)
1858
 */
1859
static int IPOnlyTestSig08(void)
1860
{
1861
    int result = 0;
1862
    uint8_t *buf = (uint8_t *)"Hi all!";
1863
    uint16_t buflen = strlen((char *)buf);
1864

1865
    uint8_t numpkts = 1;
1866
    uint8_t numsigs = 7;
1867

1868
    Packet *p[1];
1869

1870
    p[0] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP,"192.168.1.1","192.168.1.5");
1871

1872
    const char *sigs[numsigs];
1873
    sigs[0]= "alert tcp 192.168.1.5 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 1)\"; sid:1;)";
1874
    sigs[1]= "alert tcp [192.168.1.2,192.168.1.5,192.168.1.4] any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 2)\"; sid:2;)";
1875
    sigs[2]= "alert tcp [192.168.1.0/24,!192.168.1.1] any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)";
1876
    sigs[3]= "alert tcp [192.0.0.0/8,!192.168.0.0/16,192.168.1.0/24,!192.168.1.1] any -> [192.168.1.0/24,!192.168.1.5] any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)";
1877
    sigs[4]= "alert tcp any any -> !192.168.1.5 any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)";
1878
    sigs[5]= "alert tcp any any -> [192.168.0.0/16,!192.168.1.0/24,192.168.1.1] any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)";
1879
    sigs[6]= "alert tcp [78.129.202.0/24,192.168.1.5,78.129.205.64,78.129.214.103,78.129.223.19,78.129.233.17,78.137.168.33,78.140.132.11,78.140.133.15,78.140.138.105,78.140.139.105,78.140.141.107,78.140.141.114,78.140.143.103,78.140.143.13,78.140.145.144,78.140.170.164,78.140.23.18,78.143.16.7,78.143.46.124,78.157.129.71] any -> 192.168.1.1 any (msg:\"ET RBN Known Russian Business Network IP TCP - BLOCKING (246)\"; sid:7;)"; /* real sid:"2407490" */
1880

1881
    /* Sid numbers (we could extract them from the sig) */
1882
    uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7};
1883
    uint32_t results[7] = { 0, 0, 0, 0, 0, 0, 0};
1884

1885
    result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
1886

1887
    UTHFreePackets(p, numpkts);
1888

1889
    return result;
1890
}
1891

1892
/**
1893
 * \test Test a set of ip only signatures making use a lot of
1894
 * addresses for src and dst (all should match)
1895
 */
1896
static int IPOnlyTestSig09(void)
1897
{
1898
    int result = 0;
1899
    uint8_t *buf = (uint8_t *)"Hi all!";
1900
    uint16_t buflen = strlen((char *)buf);
1901

1902
    uint8_t numpkts = 1;
1903
    uint8_t numsigs = 7;
1904

1905
    Packet *p[1];
1906

1907
    p[0] = UTHBuildPacketIPV6SrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565", "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562");
1908

1909
    const char *sigs[numsigs];
1910
    sigs[0]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)";
1911
    sigs[1]= "alert tcp any any -> 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)";
1912
    sigs[2]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)";
1913
    sigs[3]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> 3FFE:FFFF:7654:FEDA:1245:BA98:3210:0/96 any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)";
1914
    sigs[4]= "alert tcp 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)";
1915
    sigs[5]= "alert tcp any any -> 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)";
1916
    sigs[6]= "alert tcp 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any -> 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any (msg:\"Testing src/dst ip (sid 7)\"; content:\"Hi all\";sid:7;)";
1917

1918
    /* Sid numbers (we could extract them from the sig) */
1919
    uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7};
1920
    uint32_t results[7] = { 1, 1, 1, 1, 1, 1, 1};
1921

1922
    result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
1923

1924
    UTHFreePackets(p, numpkts);
1925

1926
    return result;
1927
}
1928

1929
/**
1930
 * \test Test a set of ip only signatures making use a lot of
1931
 * addresses for src and dst (none should match)
1932
 */
1933
static int IPOnlyTestSig10(void)
1934
{
1935
    int result = 0;
1936
    uint8_t *buf = (uint8_t *)"Hi all!";
1937
    uint16_t buflen = strlen((char *)buf);
1938

1939
    uint8_t numpkts = 1;
1940
    uint8_t numsigs = 7;
1941

1942
    Packet *p[1];
1943

1944
    p[0] = UTHBuildPacketIPV6SrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562", "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565");
1945

1946
    const char *sigs[numsigs];
1947
    sigs[0]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)";
1948
    sigs[1]= "alert tcp any any -> 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)";
1949
    sigs[2]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562 any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)";
1950
    sigs[3]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565 any -> !3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562/96 any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)";
1951
    sigs[4]= "alert tcp !3FFE:FFFF:7654:FEDA:0:0:0:0/64 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)";
1952
    sigs[5]= "alert tcp any any -> !3FFE:FFFF:7654:FEDA:0:0:0:0/64 any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)";
1953
    sigs[6]= "alert tcp 3FFE:FFFF:7654:FEDA:0:0:0:0/64 any -> 3FFE:FFFF:7654:FEDB:0:0:0:0/64 any (msg:\"Testing src/dst ip (sid 7)\"; content:\"Hi all\";sid:7;)";
1954

1955
    /* Sid numbers (we could extract them from the sig) */
1956
    uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7};
1957
    uint32_t results[7] = { 0, 0, 0, 0, 0, 0, 0};
1958

1959
    result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
1960

1961
    UTHFreePackets(p, numpkts);
1962

1963
    return result;
1964
}
1965

1966
/* \todo fix it.  We have disabled this unittest because 599 exposes 608,
1967
 * which is why these unittests fail.  When we fix 608, we need to renable
1968
 * these sigs */
1969
#if 0
1970
/**
1971
 * \test Test a set of ip only signatures making use a lot of
1972
 * addresses for src and dst (all should match) with ipv4 and ipv6 mixed
1973
 */
1974
static int IPOnlyTestSig11(void)
1975
{
1976
    int result = 0;
1977
    uint8_t *buf = (uint8_t *)"Hi all!";
1978
    uint16_t buflen = strlen((char *)buf);
1979

1980
    uint8_t numpkts = 2;
1981
    uint8_t numsigs = 7;
1982

1983
    Packet *p[2];
1984

1985
    p[0] = UTHBuildPacketIPV6SrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565", "3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562");
1986
    p[1] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP,"192.168.1.1","192.168.1.5");
1987

1988
    char *sigs[numsigs];
1989
    sigs[0]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.1 any -> 3FFE:FFFF:7654:FEDA:0:0:0:0/64,192.168.1.5 any (msg:\"Testing src/dst ip (sid 1)\"; sid:1;)";
1990
    sigs[1]= "alert tcp [192.168.1.1,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.4,192.168.1.5,!192.168.1.0/24] any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.0/24] any (msg:\"Testing src/dst ip (sid 2)\"; sid:2;)";
1991
    sigs[2]= "alert tcp [3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.1] any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.5] any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)";
1992
    sigs[3]= "alert tcp [3FFE:FFFF:0:0:0:0:0:0/32,!3FFE:FFFF:7654:FEDA:0:0:0:0/64,3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.1] any -> [3FFE:FFFF:7654:FEDA:0:0:0:0/64,192.168.1.0/24,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565] any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)";
1993
    sigs[4]= "alert tcp any any -> any any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)";
1994
    sigs[5]= "alert tcp any any -> [3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:0:0:0:0/64,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.5] any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)";
1995
    sigs[6]= "alert tcp [78.129.202.0/24,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.1,78.129.205.64,78.129.214.103,78.129.223.19,78.129.233.17,78.137.168.33,78.140.132.11,78.140.133.15,78.140.138.105,78.140.139.105,78.140.141.107,78.140.141.114,78.140.143.103,78.140.143.13,78.140.145.144,78.140.170.164,78.140.23.18,78.143.16.7,78.143.46.124,78.157.129.71] any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.0.0.0/8] any (msg:\"ET RBN Known Russian Business Network IP TCP - BLOCKING (246)\"; sid:7;)"; /* real sid:"2407490" */
1996

1997
    /* Sid numbers (we could extract them from the sig) */
1998
    uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7};
1999
    uint32_t results[2][7] = {{ 1, 1, 1, 1, 1, 1, 1}, { 1, 1, 1, 1, 1, 1, 1}};
2000

2001
    result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
2002

2003
    UTHFreePackets(p, numpkts);
2004

2005
    return result;
2006
}
2007
#endif
2008

2009
/**
2010
 * \test Test a set of ip only signatures making use a lot of
2011
 * addresses for src and dst (none should match) with ipv4 and ipv6 mixed
2012
 */
2013
static int IPOnlyTestSig12(void)
2014
{
2015
    int result = 0;
2016
    uint8_t *buf = (uint8_t *)"Hi all!";
2017
    uint16_t buflen = strlen((char *)buf);
2018

2019
    uint8_t numpkts = 2;
2020
    uint8_t numsigs = 7;
2021

2022
    Packet *p[2];
2023

2024
    p[0] = UTHBuildPacketIPV6SrcDst((uint8_t *)buf, buflen, IPPROTO_TCP,"3FBE:FFFF:7654:FEDA:1245:BA98:3210:4562","3FBE:FFFF:7654:FEDA:1245:BA98:3210:4565");
2025
    p[1] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP,"195.85.1.1","80.198.1.5");
2026

2027
    const char *sigs[numsigs];
2028
    sigs[0]= "alert tcp 3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.1 any -> 3FFE:FFFF:7654:FEDA:0:0:0:0/64,192.168.1.5 any (msg:\"Testing src/dst ip (sid 1)\"; sid:1;)";
2029
    sigs[1]= "alert tcp [192.168.1.1,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.4,192.168.1.5,!192.168.1.0/24] any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.0/24] any (msg:\"Testing src/dst ip (sid 2)\"; sid:2;)";
2030
    sigs[2]= "alert tcp [3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.1] any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.5] any (msg:\"Testing src/dst ip (sid 3)\"; sid:3;)";
2031
    sigs[3]= "alert tcp [3FFE:FFFF:0:0:0:0:0:0/32,!3FFE:FFFF:7654:FEDA:0:0:0:0/64,3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.1] any -> [3FFE:FFFF:7654:FEDA:0:0:0:0/64,192.168.1.0/24,!3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565] any (msg:\"Testing src/dst ip (sid 4)\"; sid:4;)";
2032
    sigs[4]= "alert tcp any any -> [!3FBE:FFFF:7654:FEDA:1245:BA98:3210:4565,!80.198.1.5] any (msg:\"Testing src/dst ip (sid 5)\"; sid:5;)";
2033
    sigs[5]= "alert tcp any any -> [3FFE:FFFF:7654:FEDA:0:0:0:0/64,!3FFE:FFFF:7654:FEDA:0:0:0:0/64,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.168.1.5] any (msg:\"Testing src/dst ip (sid 6)\"; sid:6;)";
2034
    sigs[6]= "alert tcp [78.129.202.0/24,3FFE:FFFF:7654:FEDA:1245:BA98:3210:4565,192.168.1.1,78.129.205.64,78.129.214.103,78.129.223.19,78.129.233.17,78.137.168.33,78.140.132.11,78.140.133.15,78.140.138.105,78.140.139.105,78.140.141.107,78.140.141.114,78.140.143.103,78.140.143.13,78.140.145.144,78.140.170.164,78.140.23.18,78.143.16.7,78.143.46.124,78.157.129.71] any -> [3FFE:FFFF:7654:FEDA:1245:BA98:3210:4562,192.0.0.0/8] any (msg:\"ET RBN Known Russian Business Network IP TCP - BLOCKING (246)\"; sid:7;)"; /* real sid:"2407490" */
2035

2036
    /* Sid numbers (we could extract them from the sig) */
2037
    uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7};
2038
    uint32_t results[2][7] = {{ 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}};
2039

2040
    result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
2041

2042
    UTHFreePackets(p, numpkts);
2043

2044
    return result;
2045
}
2046

2047
static int IPOnlyTestSig13(void)
2048
{
2049
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2050
    FAIL_IF(de_ctx == NULL);
2051
    de_ctx->flags |= DE_QUIET;
2052

2053
    Signature *s = SigInit(de_ctx,
2054
                           "alert tcp any any -> any any (msg:\"Test flowbits ip only\"; "
2055
                           "flowbits:set,myflow1; sid:1; rev:1;)");
2056
    FAIL_IF(s == NULL);
2057

2058
    FAIL_IF(SignatureIsIPOnly(de_ctx, s) == 0);
2059
    SigFree(de_ctx, s);
2060
    DetectEngineCtxFree(de_ctx);
2061
    PASS;
2062
}
2063

2064
static int IPOnlyTestSig14(void)
2065
{
2066
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2067
    FAIL_IF(de_ctx == NULL);
2068
    de_ctx->flags |= DE_QUIET;
2069

2070
    Signature *s = SigInit(de_ctx,
2071
                           "alert tcp any any -> any any (msg:\"Test flowbits ip only\"; "
2072
                           "flowbits:set,myflow1; flowbits:isset,myflow2; sid:1; rev:1;)");
2073
    FAIL_IF(s == NULL);
2074

2075
    FAIL_IF(SignatureIsIPOnly(de_ctx, s) == 1);
2076
    SigFree(de_ctx, s);
2077
    DetectEngineCtxFree(de_ctx);
2078
    PASS;
2079
}
2080

2081
static int IPOnlyTestSig15(void)
2082
{
2083
    int result = 0;
2084
    uint8_t *buf = (uint8_t *)"Hi all!";
2085
    uint16_t buflen = strlen((char *)buf);
2086

2087
    uint8_t numpkts = 1;
2088
    uint8_t numsigs = 7;
2089

2090
    Packet *p[1];
2091
    Flow f;
2092
    GenericVar flowvar;
2093
    memset(&f, 0, sizeof(Flow));
2094
    memset(&flowvar, 0, sizeof(GenericVar));
2095
    FLOW_INITIALIZE(&f);
2096

2097
    p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP);
2098

2099
    p[0]->flow = &f;
2100
    p[0]->flow->flowvar = &flowvar;
2101
    p[0]->flags |= PKT_HAS_FLOW;
2102
    p[0]->flowflags |= (FLOW_PKT_TOSERVER | FLOW_PKT_TOSERVER_FIRST);
2103

2104
    const char *sigs[numsigs];
2105
    sigs[0]= "alert tcp 192.168.1.5 any -> any any (msg:\"Testing src ip (sid 1)\"; "
2106
        "flowbits:set,one; sid:1;)";
2107
    sigs[1]= "alert tcp any any -> 192.168.1.1 any (msg:\"Testing dst ip (sid 2)\"; "
2108
        "flowbits:set,two; sid:2;)";
2109
    sigs[2]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 3)\"; "
2110
        "flowbits:set,three; sid:3;)";
2111
    sigs[3]= "alert tcp 192.168.1.5 any -> 192.168.1.1 any (msg:\"Testing src/dst ip (sid 4)\"; "
2112
        "flowbits:set,four; sid:4;)";
2113
    sigs[4]= "alert tcp 192.168.1.0/24 any -> any any (msg:\"Testing src/dst ip (sid 5)\"; "
2114
        "flowbits:set,five; sid:5;)";
2115
    sigs[5]= "alert tcp any any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 6)\"; "
2116
        "flowbits:set,six; sid:6;)";
2117
    sigs[6]= "alert tcp 192.168.1.0/24 any -> 192.168.0.0/16 any (msg:\"Testing src/dst ip (sid 7)\"; "
2118
        "flowbits:set,seven; content:\"Hi all\"; sid:7;)";
2119

2120
    /* Sid numbers (we could extract them from the sig) */
2121
    uint32_t sid[7] = { 1, 2, 3, 4, 5, 6, 7};
2122
    uint32_t results[7] = { 1, 1, 1, 1, 1, 1, 1};
2123

2124
    result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
2125

2126
    UTHFreePackets(p, numpkts);
2127

2128
    FLOW_DESTROY(&f);
2129
    return result;
2130
}
2131

2132
/**
2133
 * \brief Unittest to show #599.  We fail to match if we have negated addresses.
2134
 */
2135
static int IPOnlyTestSig16(void)
2136
{
2137
    int result = 0;
2138
    uint8_t *buf = (uint8_t *)"Hi all!";
2139
    uint16_t buflen = strlen((char *)buf);
2140

2141
    uint8_t numpkts = 1;
2142
    uint8_t numsigs = 2;
2143

2144
    Packet *p[1];
2145

2146
    p[0] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "100.100.0.0", "50.0.0.0");
2147

2148
    const char *sigs[numsigs];
2149
    sigs[0]= "alert tcp !100.100.0.1 any -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)";
2150
    sigs[1]= "alert tcp any any -> !50.0.0.1 any (msg:\"Testing dst ip (sid 2)\"; sid:2;)";
2151

2152
    /* Sid numbers (we could extract them from the sig) */
2153
    uint32_t sid[2] = { 1, 2};
2154
    uint32_t results[2] = { 1, 1};
2155

2156
    result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
2157

2158
    UTHFreePackets(p, numpkts);
2159

2160
    return result;
2161
}
2162

2163
/**
2164
 * \brief Unittest to show #611. Ports on portless protocols.
2165
 */
2166
static int IPOnlyTestSig17(void)
2167
{
2168
    int result = 0;
2169
    uint8_t *buf = (uint8_t *)"Hi all!";
2170
    uint16_t buflen = strlen((char *)buf);
2171

2172
    uint8_t numpkts = 1;
2173
    uint8_t numsigs = 2;
2174

2175
    Packet *p[1];
2176

2177
    p[0] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_ICMP, "100.100.0.0", "50.0.0.0");
2178

2179
    const char *sigs[numsigs];
2180
    sigs[0]= "alert ip 100.100.0.0 80 -> any any (msg:\"Testing src ip (sid 1)\"; sid:1;)";
2181
    sigs[1]= "alert ip any any -> 50.0.0.0 123 (msg:\"Testing dst ip (sid 2)\"; sid:2;)";
2182

2183
    uint32_t sid[2] = { 1, 2};
2184
    uint32_t results[2] = { 0, 0}; /* neither should match */
2185

2186
    result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
2187

2188
    UTHFreePackets(p, numpkts);
2189

2190
    return result;
2191
}
2192

2193
/**
2194
 * \brief Unittest to show #3568 -- IP address range handling
2195
 */
2196
static int IPOnlyTestSig18(void)
2197
{
2198
    int result = 0;
2199
    uint8_t *buf = (uint8_t *)"Hi all!";
2200
    uint16_t buflen = strlen((char *)buf);
2201

2202
    uint8_t numpkts = 4;
2203
    uint8_t numsigs = 4;
2204

2205
    Packet *p[4];
2206

2207
    p[0] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "10.10.10.1", "50.0.0.1");
2208
    p[1] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "220.10.10.1", "5.0.0.1");
2209
    p[2] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "0.0.0.1", "50.0.0.1");
2210
    p[3] = UTHBuildPacketSrcDst((uint8_t *)buf, buflen, IPPROTO_TCP, "255.255.255.254", "5.0.0.1");
2211

2212
    const char *sigs[numsigs];
2213
    // really many IP addresses
2214
    sigs[0]= "alert ip 1.2.3.4-219.6.7.8 any -> any any (sid:1;)";
2215
    sigs[1]= "alert ip 51.2.3.4-253.1.2.3 any -> any any (sid:2;)";
2216
    sigs[2]= "alert ip 0.0.0.0-50.0.0.2 any -> any any (sid:3;)";
2217
    sigs[3]= "alert ip 50.0.0.0-255.255.255.255 any -> any any (sid:4;)";
2218

2219
    uint32_t sid[4] = { 1, 2, 3, 4, };
2220
    uint32_t results[4][4] = {
2221
        { 1, 0, 1, 0, }, { 0, 1, 0, 1}, { 0, 0, 1, 0 }, { 0, 0, 0, 1}};
2222

2223
    result = UTHGenericTest(p, numpkts, sigs, sid, (uint32_t *) results, numsigs);
2224

2225
    UTHFreePackets(p, numpkts);
2226

2227
    FAIL_IF(result != 1);
2228

2229
    PASS;
2230
}
2231

2232
/** \test build IP-only tree */
2233
static int IPOnlyTestBug5066v1(void)
2234
{
2235
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
2236
    FAIL_IF(de_ctx == NULL);
2237
    de_ctx->flags |= DE_QUIET;
2238

2239
    Signature *s = DetectEngineAppendSig(
2240
            de_ctx, "alert ip [1.2.3.4/24,1.2.3.64/27] any -> any any (sid:1;)");
2241
    FAIL_IF_NULL(s);
2242
    s = DetectEngineAppendSig(de_ctx, "alert ip [1.2.3.4/24] any -> any any (sid:2;)");
2243
    FAIL_IF_NULL(s);
2244

2245
    SigGroupBuild(de_ctx);
2246

2247
    DetectEngineCtxFree(de_ctx);
2248
    PASS;
2249
}
2250

2251
static int IPOnlyTestBug5066v2(void)
2252
{
2253
    IPOnlyCIDRItem *x = IPOnlyCIDRItemNew();
2254
    FAIL_IF_NULL(x);
2255

2256
    FAIL_IF(IPOnlyCIDRItemParseSingle(&x, "1.2.3.4/24") != 0);
2257

2258
    char ip[16];
2259
    PrintInet(AF_INET, (const void *)&x->ip[0], ip, sizeof(ip));
2260
    SCLogDebug("ip %s netmask %d", ip, x->netmask);
2261

2262
    FAIL_IF_NOT(strcmp(ip, "1.2.3.0") == 0);
2263
    FAIL_IF_NOT(x->netmask == 24);
2264

2265
    IPOnlyCIDRListFree(x);
2266
    PASS;
2267
}
2268

2269
static int IPOnlyTestBug5066v3(void)
2270
{
2271
    IPOnlyCIDRItem *x = IPOnlyCIDRItemNew();
2272
    FAIL_IF_NULL(x);
2273

2274
    FAIL_IF(IPOnlyCIDRItemParseSingle(&x, "1.2.3.64/26") != 0);
2275

2276
    char ip[16];
2277
    PrintInet(AF_INET, (const void *)&x->ip[0], ip, sizeof(ip));
2278
    SCLogDebug("ip %s netmask %d", ip, x->netmask);
2279

2280
    FAIL_IF_NOT(strcmp(ip, "1.2.3.64") == 0);
2281
    FAIL_IF_NOT(x->netmask == 26);
2282

2283
    IPOnlyCIDRListFree(x);
2284
    PASS;
2285
}
2286

2287
static int IPOnlyTestBug5066v4(void)
2288
{
2289
    IPOnlyCIDRItem *x = IPOnlyCIDRItemNew();
2290
    FAIL_IF_NULL(x);
2291

2292
    FAIL_IF(IPOnlyCIDRItemParseSingle(&x, "2000::1:1/122") != 0);
2293

2294
    char ip[64];
2295
    PrintInet(AF_INET6, (const void *)&x->ip, ip, sizeof(ip));
2296
    SCLogDebug("ip %s netmask %d", ip, x->netmask);
2297

2298
    FAIL_IF_NOT(strcmp(ip, "2000:0000:0000:0000:0000:0000:0001:0000") == 0);
2299
    FAIL_IF_NOT(x->netmask == 122);
2300

2301
    IPOnlyCIDRListFree(x);
2302
    PASS;
2303
}
2304

2305
static int IPOnlyTestBug5066v5(void)
2306
{
2307
    IPOnlyCIDRItem *x = IPOnlyCIDRItemNew();
2308
    FAIL_IF_NULL(x);
2309

2310
    FAIL_IF(IPOnlyCIDRItemParseSingle(&x, "2000::1:40/122") != 0);
2311

2312
    char ip[64];
2313
    PrintInet(AF_INET6, (const void *)&x->ip, ip, sizeof(ip));
2314
    SCLogDebug("ip %s netmask %d", ip, x->netmask);
2315

2316
    FAIL_IF_NOT(strcmp(ip, "2000:0000:0000:0000:0000:0000:0001:0040") == 0);
2317
    FAIL_IF_NOT(x->netmask == 122);
2318

2319
    IPOnlyCIDRListFree(x);
2320
    PASS;
2321
}
2322

2323
static int IPOnlyTestBug5168v1(void)
2324
{
2325
    IPOnlyCIDRItem *x = IPOnlyCIDRItemNew();
2326
    FAIL_IF_NULL(x);
2327

2328
    FAIL_IF(IPOnlyCIDRItemParseSingle(&x, "1.2.3.64/0.0.0.0") != 0);
2329

2330
    char ip[16];
2331
    PrintInet(AF_INET, (const void *)&x->ip[0], ip, sizeof(ip));
2332
    SCLogDebug("ip %s netmask %d", ip, x->netmask);
2333

2334
    FAIL_IF_NOT(strcmp(ip, "0.0.0.0") == 0);
2335
    FAIL_IF_NOT(x->netmask == 0);
2336

2337
    IPOnlyCIDRListFree(x);
2338
    PASS;
2339
}
2340

2341
static int IPOnlyTestBug5168v2(void)
2342
{
2343
    IPOnlyCIDRItem *x = IPOnlyCIDRItemNew();
2344
    FAIL_IF_NULL(x);
2345
    FAIL_IF(IPOnlyCIDRItemParseSingle(&x, "0.0.0.5/0.0.0.5") != -1);
2346
    IPOnlyCIDRListFree(x);
2347
    PASS;
2348
}
2349

2350
#endif /* UNITTESTS */
2351

2352
void IPOnlyRegisterTests(void)
2353
{
×
2354
#ifdef UNITTESTS
2355
    UtRegisterTest("IPOnlyTestSig01", IPOnlyTestSig01);
2356
    UtRegisterTest("IPOnlyTestSig02", IPOnlyTestSig02);
2357
    UtRegisterTest("IPOnlyTestSig03", IPOnlyTestSig03);
2358
    UtRegisterTest("IPOnlyTestSig04", IPOnlyTestSig04);
2359

2360
    UtRegisterTest("IPOnlyTestSig05", IPOnlyTestSig05);
2361
    UtRegisterTest("IPOnlyTestSig06", IPOnlyTestSig06);
2362
/* \todo fix it.  We have disabled this unittest because 599 exposes 608,
2363
 * which is why these unittests fail.  When we fix 608, we need to renable
2364
 * these sigs */
2365
#if 0
2366
    UtRegisterTest("IPOnlyTestSig07", IPOnlyTestSig07, 1);
2367
#endif
2368
    UtRegisterTest("IPOnlyTestSig08", IPOnlyTestSig08);
2369

2370
    UtRegisterTest("IPOnlyTestSig09", IPOnlyTestSig09);
2371
    UtRegisterTest("IPOnlyTestSig10", IPOnlyTestSig10);
2372
/* \todo fix it.  We have disabled this unittest because 599 exposes 608,
2373
 * which is why these unittests fail.  When we fix 608, we need to renable
2374
 * these sigs */
2375
#if 0
2376
    UtRegisterTest("IPOnlyTestSig11", IPOnlyTestSig11, 1);
2377
#endif
2378
    UtRegisterTest("IPOnlyTestSig12", IPOnlyTestSig12);
2379
    UtRegisterTest("IPOnlyTestSig13", IPOnlyTestSig13);
2380
    UtRegisterTest("IPOnlyTestSig14", IPOnlyTestSig14);
2381
    UtRegisterTest("IPOnlyTestSig15", IPOnlyTestSig15);
2382
    UtRegisterTest("IPOnlyTestSig16", IPOnlyTestSig16);
2383

2384
    UtRegisterTest("IPOnlyTestSig17", IPOnlyTestSig17);
2385
    UtRegisterTest("IPOnlyTestSig18", IPOnlyTestSig18);
2386

2387
    UtRegisterTest("IPOnlyTestBug5066v1", IPOnlyTestBug5066v1);
2388
    UtRegisterTest("IPOnlyTestBug5066v2", IPOnlyTestBug5066v2);
2389
    UtRegisterTest("IPOnlyTestBug5066v3", IPOnlyTestBug5066v3);
2390
    UtRegisterTest("IPOnlyTestBug5066v4", IPOnlyTestBug5066v4);
2391
    UtRegisterTest("IPOnlyTestBug5066v5", IPOnlyTestBug5066v5);
2392

2393
    UtRegisterTest("IPOnlyTestBug5168v1", IPOnlyTestBug5168v1);
2394
    UtRegisterTest("IPOnlyTestBug5168v2", IPOnlyTestBug5168v2);
2395
#endif
2396
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc