Coverage Report

Created: 2025-12-31 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/util-unittest-helper.c
Line
Count
Source
1
/* Copyright (C) 2007-2017 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 Pablo Rincon Crespo <pablo.rincon.crespo@gmail.com>
22
 *
23
 * This file provide a set of helper functions for reducing the complexity
24
 * when constructing unittests
25
 */
26
27
#include "suricata-common.h"
28
29
#include "decode.h"
30
31
#include "flow-private.h"
32
#include "flow-util.h"
33
#include "flow-spare-pool.h"
34
35
#include "detect.h"
36
#include "detect-parse.h"
37
#include "detect-engine.h"
38
#include "detect-engine-alert.h"
39
#include "detect-engine-sigorder.h"
40
#include "detect-engine-build.h"
41
42
#include "stream-tcp.h"
43
#include "stream-tcp-private.h"
44
45
#include "util-debug.h"
46
#include "util-time.h"
47
#include "util-error.h"
48
#include "util-unittest.h"
49
#include "util-unittest-helper.h"
50
51
#if defined(UNITTESTS) || defined(FUZZ)
52
Flow *TestHelperBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)
53
24.9k
{
54
24.9k
    struct in_addr in;
55
56
24.9k
    Flow *f = SCMalloc(sizeof(Flow));
57
24.9k
    if (unlikely(f == NULL)) {
58
0
        printf("FlowAlloc failed\n");
59
0
        ;
60
0
        return NULL;
61
0
    }
62
24.9k
    memset(f, 0x00, sizeof(Flow));
63
64
24.9k
    FLOW_INITIALIZE(f);
65
66
24.9k
    if (family == AF_INET) {
67
24.9k
        f->flags |= FLOW_IPV4;
68
24.9k
    } else if (family == AF_INET6) {
69
0
        f->flags |= FLOW_IPV6;
70
0
    }
71
72
24.9k
    if (src != NULL) {
73
24.9k
        if (family == AF_INET) {
74
24.9k
            if (inet_pton(AF_INET, src, &in) != 1) {
75
0
                printf("invalid address %s\n", src);
76
0
                SCFree(f);
77
0
                return NULL;
78
0
            }
79
24.9k
            f->src.addr_data32[0] = in.s_addr;
80
24.9k
        } else {
81
0
            BUG_ON(1);
82
0
        }
83
24.9k
    }
84
24.9k
    if (dst != NULL) {
85
24.9k
        if (family == AF_INET) {
86
24.9k
            if (inet_pton(AF_INET, dst, &in) != 1) {
87
0
                printf("invalid address %s\n", dst);
88
0
                SCFree(f);
89
0
                return NULL;
90
0
            }
91
24.9k
            f->dst.addr_data32[0] = in.s_addr;
92
24.9k
        } else {
93
0
            BUG_ON(1);
94
0
        }
95
24.9k
    }
96
97
24.9k
    f->sp = sp;
98
24.9k
    f->dp = dp;
99
100
24.9k
    return f;
101
24.9k
}
102
/** \brief writes the contents of a buffer into a file */
103
int TestHelperBufferToFile(const char *name, const uint8_t *data, size_t size)
104
217k
{
105
217k
    if (remove(name) != 0) {
106
2.12k
        if (errno != ENOENT) {
107
0
            printf("failed remove, errno=%d\n", errno);
108
0
            return -1;
109
0
        }
110
2.12k
    }
111
217k
    FILE *fd = fopen(name, "wb");
112
217k
    if (fd == NULL) {
113
0
        printf("failed open, errno=%d\n", errno);
114
0
        return -2;
115
0
    }
116
217k
    if (fwrite (data, 1, size, fd) != size) {
117
0
        fclose(fd);
118
0
        return -3;
119
0
    }
120
217k
    fclose(fd);
121
217k
    return 0;
122
217k
}
123
124
#endif
125
#ifdef UNITTESTS
126
127
/**
128
 *  \brief return the uint32_t for a ipv4 address string
129
 *
130
 *  \param str Valid ipaddress in string form (e.g. 1.2.3.4)
131
 *
132
 *  \retval uint the uin32_t representation
133
 */
134
uint32_t UTHSetIPv4Address(const char *str)
135
{
136
    struct in_addr in;
137
    if (inet_pton(AF_INET, str, &in) != 1) {
138
        printf("invalid IPv6 address %s\n", str);
139
        exit(EXIT_FAILURE);
140
    }
141
    return (uint32_t)in.s_addr;
142
}
143
144
/**
145
 * \brief UTHBuildPacketReal is a function that create tcp/udp packets for unittests
146
 * specifying ip and port sources and destinations (IPV6)
147
 *
148
 * \param payload pointer to the payload buffer
149
 * \param payload_len pointer to the length of the payload
150
 * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
151
 * \param src pointer to a string containing the ip source
152
 * \param dst pointer to a string containing the ip destination
153
 * \param sport pointer to a string containing the port source
154
 * \param dport pointer to a string containing the port destination
155
 *
156
 * \retval Packet pointer to the built in packet
157
 */
158
Packet *UTHBuildPacketIPV6Real(uint8_t *payload, uint16_t payload_len,
159
                           uint8_t ipproto, const char *src, const char *dst,
160
                           uint16_t sport, uint16_t dport)
161
{
162
    uint32_t in[4];
163
164
    Packet *p = PacketGetFromAlloc();
165
    if (unlikely(p == NULL))
166
        return NULL;
167
168
    p->ts = TimeGet();
169
170
    p->src.family = AF_INET6;
171
    p->dst.family = AF_INET6;
172
    p->payload = payload;
173
    p->payload_len = payload_len;
174
    p->proto = ipproto;
175
176
    p->ip6h = SCMalloc(sizeof(IPV6Hdr));
177
    if (p->ip6h == NULL)
178
        goto error;
179
    memset(p->ip6h, 0, sizeof(IPV6Hdr));
180
    p->ip6h->s_ip6_nxt = ipproto;
181
    p->ip6h->s_ip6_plen = htons(payload_len + sizeof(TCPHdr));
182
183
    if (inet_pton(AF_INET6, src, &in) != 1)
184
        goto error;
185
    p->src.addr_data32[0] = in[0];
186
    p->src.addr_data32[1] = in[1];
187
    p->src.addr_data32[2] = in[2];
188
    p->src.addr_data32[3] = in[3];
189
    p->sp = sport;
190
    p->ip6h->s_ip6_src[0] = in[0];
191
    p->ip6h->s_ip6_src[1] = in[1];
192
    p->ip6h->s_ip6_src[2] = in[2];
193
    p->ip6h->s_ip6_src[3] = in[3];
194
195
    if (inet_pton(AF_INET6, dst, &in) != 1)
196
        goto error;
197
    p->dst.addr_data32[0] = in[0];
198
    p->dst.addr_data32[1] = in[1];
199
    p->dst.addr_data32[2] = in[2];
200
    p->dst.addr_data32[3] = in[3];
201
    p->dp = dport;
202
    p->ip6h->s_ip6_dst[0] = in[0];
203
    p->ip6h->s_ip6_dst[1] = in[1];
204
    p->ip6h->s_ip6_dst[2] = in[2];
205
    p->ip6h->s_ip6_dst[3] = in[3];
206
207
    p->tcph = SCMalloc(sizeof(TCPHdr));
208
    if (p->tcph == NULL)
209
        goto error;
210
    memset(p->tcph, 0, sizeof(TCPHdr));
211
    p->tcph->th_sport = htons(sport);
212
    p->tcph->th_dport = htons(dport);
213
214
    SET_PKT_LEN(p, sizeof(IPV6Hdr) + sizeof(TCPHdr) + payload_len);
215
    return p;
216
217
error:
218
    if (p != NULL) {
219
        if (p->ip6h != NULL) {
220
            SCFree(p->ip6h);
221
        }
222
        if (p->tcph != NULL) {
223
            SCFree(p->tcph);
224
        }
225
        SCFree(p);
226
    }
227
    return NULL;
228
}
229
230
/**
231
 * \brief UTHBuildPacketReal is a function that create tcp/udp packets for unittests
232
 * specifying ip and port sources and destinations
233
 *
234
 * \param payload pointer to the payload buffer
235
 * \param payload_len pointer to the length of the payload
236
 * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
237
 * \param src pointer to a string containing the ip source
238
 * \param dst pointer to a string containing the ip destination
239
 * \param sport pointer to a string containing the port source
240
 * \param dport pointer to a string containing the port destination
241
 *
242
 * \retval Packet pointer to the built in packet
243
 */
244
Packet *UTHBuildPacketReal(uint8_t *payload, uint16_t payload_len,
245
                           uint8_t ipproto, const char *src, const char *dst,
246
                           uint16_t sport, uint16_t dport)
247
{
248
    struct in_addr in;
249
250
    Packet *p = PacketGetFromAlloc();
251
    if (unlikely(p == NULL))
252
        return NULL;
253
254
    p->ts = TimeGet();
255
256
    p->src.family = AF_INET;
257
    p->dst.family = AF_INET;
258
    p->payload = payload;
259
    p->payload_len = payload_len;
260
    p->proto = ipproto;
261
262
    if (inet_pton(AF_INET, src, &in) != 1)
263
        goto error;
264
    p->src.addr_data32[0] = in.s_addr;
265
    p->sp = sport;
266
267
    if (inet_pton(AF_INET, dst, &in) != 1)
268
        goto error;
269
    p->dst.addr_data32[0] = in.s_addr;
270
    p->dp = dport;
271
272
    p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
273
    if (p->ip4h == NULL)
274
        goto error;
275
276
    p->ip4h->s_ip_src.s_addr = p->src.addr_data32[0];
277
    p->ip4h->s_ip_dst.s_addr = p->dst.addr_data32[0];
278
    p->ip4h->ip_proto = ipproto;
279
    p->ip4h->ip_verhl = sizeof(IPV4Hdr);
280
    p->proto = ipproto;
281
282
    int hdr_offset = sizeof(IPV4Hdr);
283
    switch (ipproto) {
284
        case IPPROTO_UDP:
285
            p->udph = (UDPHdr *)(GET_PKT_DATA(p) + sizeof(IPV4Hdr));
286
            if (p->udph == NULL)
287
                goto error;
288
289
            p->udph->uh_sport = sport;
290
            p->udph->uh_dport = dport;
291
            hdr_offset += sizeof(UDPHdr);
292
            break;
293
        case IPPROTO_TCP:
294
            p->tcph = (TCPHdr *)(GET_PKT_DATA(p) + sizeof(IPV4Hdr));
295
            if (p->tcph == NULL)
296
                goto error;
297
298
            p->tcph->th_sport = htons(sport);
299
            p->tcph->th_dport = htons(dport);
300
            hdr_offset += sizeof(TCPHdr);
301
            break;
302
        case IPPROTO_ICMP:
303
            p->icmpv4h = (ICMPV4Hdr *)(GET_PKT_DATA(p) + sizeof(IPV4Hdr));
304
            if (p->icmpv4h == NULL)
305
                goto error;
306
307
            hdr_offset += sizeof(ICMPV4Hdr);
308
            break;
309
        default:
310
            break;
311
        /* TODO: Add more protocols */
312
    }
313
314
    if (payload && payload_len) {
315
        PacketCopyDataOffset(p, hdr_offset, payload, payload_len);
316
    }
317
    SET_PKT_LEN(p, hdr_offset + payload_len);
318
    p->payload = GET_PKT_DATA(p)+hdr_offset;
319
    p->app_update_direction = UPDATE_DIR_BOTH;
320
321
    return p;
322
323
error:
324
    SCFree(p);
325
    return NULL;
326
}
327
328
/**
329
 * \brief UTHBuildPacket is a wrapper that build packets with default ip
330
 * and port fields
331
 *
332
 * \param payload pointer to the payload buffer
333
 * \param payload_len pointer to the length of the payload
334
 * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
335
 *
336
 * \retval Packet pointer to the built in packet
337
 */
338
Packet *UTHBuildPacket(uint8_t *payload, uint16_t payload_len,
339
                           uint8_t ipproto)
340
{
341
    return UTHBuildPacketReal(payload, payload_len, ipproto,
342
                              "192.168.1.5", "192.168.1.1",
343
                              41424, 80);
344
}
345
346
/**
347
 * \brief UTHBuildPacketArrayFromEth is a wrapper that build a packets from an array of
348
 *        packets in ethernet rawbytes. Hint: It also share the flows.
349
 *
350
 * \param raw_eth pointer to the array of ethernet packets in rawbytes
351
 * \param pktsize pointer to the array of sizes corresponding to each buffer pointed
352
 *                from pktsize.
353
 * \param numpkts number of packets in the array
354
 *
355
 * \retval Packet pointer to the array of built in packets; NULL if something fail
356
 */
357
Packet **UTHBuildPacketArrayFromEth(uint8_t *raw_eth[], int *pktsize, int numpkts)
358
{
359
    DecodeThreadVars dtv;
360
    ThreadVars th_v;
361
    if (raw_eth == NULL || pktsize == NULL || numpkts <= 0) {
362
        SCLogError("The arrays cant be null, and the number"
363
                   " of packets should be grater thatn zero");
364
        return NULL;
365
    }
366
    Packet **p = NULL;
367
    p = SCMalloc(sizeof(Packet *) * numpkts);
368
    if (unlikely(p == NULL))
369
        return NULL;
370
371
    memset(&dtv, 0, sizeof(DecodeThreadVars));
372
    memset(&th_v, 0, sizeof(th_v));
373
374
    int i = 0;
375
    for (; i < numpkts; i++) {
376
        p[i] = PacketGetFromAlloc();
377
        if (p[i] == NULL) {
378
            SCFree(p);
379
            return NULL;
380
        }
381
        DecodeEthernet(&th_v, &dtv, p[i], raw_eth[i], pktsize[i]);
382
    }
383
    return p;
384
}
385
386
/**
387
 * \brief UTHBuildPacketFromEth is a wrapper that build a packet for the rawbytes
388
 *
389
 * \param raw_eth pointer to the rawbytes containing an ethernet packet
390
 *                    (and any other headers inside)
391
 * \param pktsize pointer to the length of the payload
392
 *
393
 * \retval Packet pointer to the built in packet; NULL if something fail
394
 */
395
Packet *UTHBuildPacketFromEth(uint8_t *raw_eth, uint16_t pktsize)
396
{
397
    DecodeThreadVars dtv;
398
    ThreadVars th_v;
399
    Packet *p = PacketGetFromAlloc();
400
    if (unlikely(p == NULL))
401
        return NULL;
402
    memset(&dtv, 0, sizeof(DecodeThreadVars));
403
    memset(&th_v, 0, sizeof(th_v));
404
405
    DecodeEthernet(&th_v, &dtv, p, raw_eth, pktsize);
406
    return p;
407
}
408
409
/**
410
 * \brief UTHBuildPacketSrcDst is a wrapper that build packets specifying IPs
411
 * and defaulting ports
412
 *
413
 * \param payload pointer to the payload buffer
414
 * \param payload_len pointer to the length of the payload
415
 * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
416
 *
417
 * \retval Packet pointer to the built in packet
418
 */
419
Packet *UTHBuildPacketSrcDst(uint8_t *payload, uint16_t payload_len,
420
                             uint8_t ipproto, const char *src, const char *dst)
421
{
422
    return UTHBuildPacketReal(payload, payload_len, ipproto,
423
                              src, dst,
424
                              41424, 80);
425
}
426
427
/**
428
 * \brief UTHBuildPacketSrcDst is a wrapper that build packets specifying IPs
429
 * and defaulting ports (IPV6)
430
 *
431
 * \param payload pointer to the payload buffer
432
 * \param payload_len pointer to the length of the payload
433
 * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
434
 *
435
 * \retval Packet pointer to the built in packet
436
 */
437
Packet *UTHBuildPacketIPV6SrcDst(uint8_t *payload, uint16_t payload_len,
438
                           uint8_t ipproto, const char *src, const char *dst)
439
{
440
    return UTHBuildPacketIPV6Real(payload, payload_len, ipproto,
441
                              src, dst,
442
                              41424, 80);
443
}
444
445
/**
446
 * \brief UTHBuildPacketSrcDstPorts is a wrapper that build packets specifying
447
 * src and dst ports and defaulting IPs
448
 *
449
 * \param payload pointer to the payload buffer
450
 * \param payload_len pointer to the length of the payload
451
 * \param ipproto Protocols allowed atm are IPPROTO_TCP and IPPROTO_UDP
452
 *
453
 * \retval Packet pointer to the built in packet
454
 */
455
Packet *UTHBuildPacketSrcDstPorts(uint8_t *payload, uint16_t payload_len,
456
                           uint8_t ipproto, uint16_t sport, uint16_t dport)
457
{
458
    return UTHBuildPacketReal(payload, payload_len, ipproto,
459
                              "192.168.1.5", "192.168.1.1",
460
                              sport, dport);
461
}
462
463
/**
464
 * \brief UTHFreePackets: function to release the allocated data
465
 * from UTHBuildPacket and the packet itself
466
 *
467
 * \param p pointer to the Packet
468
 */
469
void UTHFreePackets(Packet **p, int numpkts)
470
{
471
    if (p == NULL)
472
        return;
473
474
    int i = 0;
475
    for (; i < numpkts; i++) {
476
        UTHFreePacket(p[i]);
477
    }
478
}
479
480
/**
481
 * \brief UTHFreePacket: function to release the allocated data
482
 * from UTHBuildPacket and the packet itself
483
 *
484
 * \param p pointer to the Packet
485
 */
486
void UTHFreePacket(Packet *p)
487
{
488
    if (p == NULL)
489
        return;
490
#if 0 // VJ we now use one buffer
491
    switch (p->proto) {
492
        case IPPROTO_UDP:
493
            if (p->udph != NULL)
494
                SCFree(p->udph);
495
            if (p->ip4h != NULL)
496
                SCFree(p->ip4h);
497
        break;
498
        case IPPROTO_TCP:
499
            if (p->tcph != NULL)
500
                SCFree(p->tcph);
501
            if (p->ip4h != NULL)
502
                SCFree(p->ip4h);
503
        break;
504
        case IPPROTO_ICMP:
505
            if (p->ip4h != NULL)
506
                SCFree(p->ip4h);
507
        break;
508
        /* TODO: Add more protocols */
509
    }
510
#endif
511
    SCFree(p);
512
}
513
514
void UTHAssignFlow(Packet *p, Flow *f)
515
{
516
    if (p && f) {
517
        p->flow = f;
518
        p->flags |= PKT_HAS_FLOW;
519
    }
520
}
521
522
Flow *UTHBuildFlow(int family, const char *src, const char *dst, Port sp, Port dp)
523
{
524
    return TestHelperBuildFlow(family, src, dst, sp, dp);
525
}
526
527
void UTHFreeFlow(Flow *flow)
528
{
529
    if (flow != NULL) {
530
        SCFree(flow);//FlowFree(flow);
531
    }
532
}
533
534
int UTHAddStreamToFlow(Flow *f, int direction,
535
    uint8_t *data, uint32_t data_len)
536
{
537
    FAIL_IF_NULL(f);
538
    FAIL_IF_NOT(f->proto == IPPROTO_TCP);
539
    FAIL_IF_NULL(f->protoctx);
540
    TcpSession *ssn = f->protoctx;
541
542
    StreamingBufferSegment seg;
543
    TcpStream *stream = direction == 0 ? &ssn->client : &ssn->server;
544
    int r = StreamingBufferAppend(&stream->sb, &stream_config.sbcnf, &seg, data, data_len);
545
    FAIL_IF_NOT(r == 0);
546
    stream->last_ack += data_len;
547
    return 1;
548
}
549
550
int UTHAddSessionToFlow(Flow *f,
551
    uint32_t ts_isn,
552
    uint32_t tc_isn)
553
{
554
    FAIL_IF_NULL(f);
555
556
    TcpSession *ssn = SCCalloc(1, sizeof(*ssn));
557
    FAIL_IF_NULL(ssn);
558
559
    StreamingBuffer x = STREAMING_BUFFER_INITIALIZER;
560
    ssn->client.sb = x;
561
    ssn->server.sb = x;
562
563
    ssn->client.isn = ts_isn;
564
    ssn->server.isn = tc_isn;
565
566
    f->protoctx = ssn;
567
    return 1;
568
}
569
570
int UTHRemoveSessionFromFlow(Flow *f)
571
{
572
    FAIL_IF_NULL(f);
573
    FAIL_IF_NOT(f->proto == IPPROTO_TCP);
574
    TcpSession *ssn = f->protoctx;
575
    FAIL_IF_NULL(ssn);
576
    StreamTcpSessionCleanup(ssn);
577
    SCFree(ssn);
578
    f->protoctx = NULL;
579
    return 1;
580
}
581
582
/**
583
 * \brief UTHGenericTest: function that perform a generic check taking care of
584
 *                      as maximum common unittest elements as possible.
585
 *                      It will create a detection engine, append an array
586
 *                      of signatures an check the expected results for each
587
 *                      of them, it check matches for an array of packets
588
 *
589
 * \param pkt pointer to the array of packets
590
 * \param numpkts number of packets to match
591
 * \param sigs array of char* pointing to signatures to load
592
 * \param numsigs number of signatures to load and check
593
 * \param results pointer to arrays of numbers, each of them foreach packet
594
 *                to check if sids matches that packet as expected with
595
 *                that number of times or not. The size of results should be
596
 *                numpkts * numsigs * sizeof(uint16_t *)
597
 *
598
 *                Example:
599
 *                result[1][3] would mean the number of times the pkt[1]
600
 *                match the sid[3]
601
 *
602
 * \retval int 1 if the match of all the sids is the specified has the
603
 *             specified results; 0 if not
604
 */
605
int UTHGenericTest(Packet **pkt, int numpkts, const char *sigs[], uint32_t sids[], uint32_t *results, int numsigs)
606
{
607
608
    int result = 0;
609
    if (pkt == NULL || sigs == NULL || numpkts == 0
610
        || sids == NULL || results == NULL || numsigs == 0) {
611
        SCLogError("Arguments invalid, that the pointer/arrays are not NULL, and the number of "
612
                   "signatures and packets is > 0");
613
        goto end;
614
    }
615
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
616
    if (de_ctx == NULL) {
617
        goto end;
618
    }
619
    de_ctx->flags |= DE_QUIET;
620
621
    if (UTHAppendSigs(de_ctx, sigs, numsigs) == 0)
622
        goto cleanup;
623
624
    result = UTHMatchPacketsWithResults(de_ctx, pkt, numpkts, sids, results, numsigs);
625
626
cleanup:
627
    DetectEngineCtxFree(de_ctx);
628
end:
629
    return result;
630
}
631
632
/**
633
 * \brief UTHCheckPacketMatches: function to check if a packet match some sids
634
 *
635
 *
636
 * \param p pointer to the Packet
637
 * \param sigs array of char* pointing to signatures to load
638
 * \param numsigs number of signatures to load from the array
639
 * \param results pointer to an array of numbers to check if sids matches
640
 *                that number of times or not.
641
 *
642
 * \retval int 1 if the match of all the sids is the specified has the
643
 *             specified results; 0 if not
644
 */
645
int UTHCheckPacketMatchResults(Packet *p, uint32_t sids[], uint32_t results[], int numsigs)
646
{
647
    if (p == NULL || sids == NULL) {
648
        SCLogError("Arguments invalid, check if the "
649
                   "packet is NULL, and if the array contain sids is set");
650
        return 0;
651
    }
652
653
    int i = 0;
654
    int res = 1;
655
    for (; i < numsigs; i++) {
656
        uint32_t r = PacketAlertCheck(p, sids[i]);
657
        if (r != results[i]) {
658
            SCLogInfo("Sid %" PRIu32 " matched %" PRIu32 " times, and not %" PRIu32 " as expected",
659
                    sids[i], r, results[i]);
660
            res = 0;
661
        } else {
662
            SCLogInfo("Sid %" PRIu32 " matched %" PRIu32 " times, as expected", sids[i], r);
663
        }
664
    }
665
    return res;
666
}
667
668
/**
669
 * \brief UTHAppendSigs: Add sigs to the detection_engine checking for errors
670
 *
671
 * \param de_ctx pointer to the DetectEngineCtx used
672
 * \param sigs array of char* pointing to signatures to load
673
 * \param numsigs number of signatures to load from the array
674
 *                (size of the array)
675
 *
676
 * \retval int 0 if we have errors; 1 if all the signatures loaded successfully
677
 */
678
int UTHAppendSigs(DetectEngineCtx *de_ctx, const char *sigs[], int numsigs)
679
{
680
    BUG_ON(de_ctx == NULL);
681
    BUG_ON(numsigs <= 0);
682
    BUG_ON(sigs == NULL);
683
684
    for (int i = 0; i < numsigs; i++) {
685
        if (sigs[i] == NULL) {
686
            SCLogError("Check the signature"
687
                       " at position %d",
688
                    i);
689
            return 0;
690
        }
691
        Signature *s = DetectEngineAppendSig(de_ctx, sigs[i]);
692
        if (s == NULL) {
693
            SCLogError("Check the signature at"
694
                       " position %d (%s)",
695
                    i, sigs[i]);
696
            return 0;
697
        }
698
    }
699
    return 1;
700
}
701
702
/**
703
 * \test UTHMatchPacketsWithResults Match a packet or a array of packets against sigs
704
 * of a de_ctx, checking that each signature matches X times for certain packets
705
 *
706
 * \param de_ctx pointer with the signatures loaded
707
 * \param p pointer to the array of packets
708
 * \param num_packets number of packets in the array
709
 *
710
 * \retval return 1 if all goes well
711
 * \retval return 0 if something fail
712
 */
713
int UTHMatchPacketsWithResults(DetectEngineCtx *de_ctx, Packet **p, int num_packets, uint32_t sids[], uint32_t *results, int numsigs)
714
{
715
    BUG_ON(de_ctx == NULL);
716
    BUG_ON(p == NULL);
717
718
    int result = 0;
719
    DecodeThreadVars dtv;
720
    ThreadVars th_v;
721
    DetectEngineThreadCtx *det_ctx = NULL;
722
    memset(&dtv, 0, sizeof(DecodeThreadVars));
723
    memset(&th_v, 0, sizeof(th_v));
724
725
    SigGroupBuild(de_ctx);
726
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
727
728
    for (int i = 0; i < num_packets; i++) {
729
        SigMatchSignatures(&th_v, de_ctx, det_ctx, p[i]);
730
        if (UTHCheckPacketMatchResults(p[i], sids, &results[(i * numsigs)], numsigs) == 0)
731
            goto cleanup;
732
    }
733
734
    result = 1;
735
cleanup:
736
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
737
    return result;
738
}
739
740
/**
741
 * \test UTHMatchPackets Match a packet or a array of packets against sigs
742
 * of a de_ctx, but note that the return value doesn't mean that we have a
743
 * match, we have to check it later with PacketAlertCheck()
744
 *
745
 * \param de_ctx pointer with the signatures loaded
746
 * \param p pointer to the array of packets
747
 * \param num_packets number of packets in the array
748
 *
749
 * \retval return 1 if all goes well
750
 * \retval return 0 if something fail
751
 */
752
int UTHMatchPackets(DetectEngineCtx *de_ctx, Packet **p, int num_packets)
753
{
754
    BUG_ON(de_ctx == NULL);
755
    BUG_ON(p == NULL);
756
    int result = 1;
757
    DecodeThreadVars dtv;
758
    ThreadVars th_v;
759
    DetectEngineThreadCtx *det_ctx = NULL;
760
    memset(&dtv, 0, sizeof(DecodeThreadVars));
761
    memset(&th_v, 0, sizeof(th_v));
762
    SCSigRegisterSignatureOrderingFuncs(de_ctx);
763
    SCSigOrderSignatures(de_ctx);
764
    SCSigSignatureOrderingModuleCleanup(de_ctx);
765
    SigGroupBuild(de_ctx);
766
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
767
768
    for (int i = 0; i < num_packets; i++)
769
        SigMatchSignatures(&th_v, de_ctx, det_ctx, p[i]);
770
771
    /* Here we don't check if the packet matched or not, because
772
     * the de_ctx can have multiple signatures, and some of them may match
773
     * and others may not. That check will be outside
774
     */
775
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
776
    if (de_ctx != NULL) SigGroupCleanup(de_ctx);
777
    return result;
778
}
779
780
/**
781
 * \test Test if a packet match a signature given as string and a mpm_type
782
 * Hint: Useful for unittests with only one packet and one signature
783
 *
784
 * \param sig pointer to the string signature to test
785
 * \param sid sid number of the signature
786
 *
787
 * \retval return 1 if match
788
 * \retval return 0 if not
789
 */
790
int UTHPacketMatchSigMpm(Packet *p, char *sig, uint16_t mpm_type)
791
{
792
    SCEnter();
793
794
    int result = 0;
795
796
    DecodeThreadVars dtv;
797
    ThreadVars th_v;
798
    DetectEngineThreadCtx *det_ctx = NULL;
799
800
    memset(&dtv, 0, sizeof(DecodeThreadVars));
801
    memset(&th_v, 0, sizeof(th_v));
802
803
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
804
    if (de_ctx == NULL) {
805
        printf("de_ctx == NULL: ");
806
        goto end;
807
    }
808
809
    de_ctx->flags |= DE_QUIET;
810
    de_ctx->mpm_matcher = mpm_type;
811
812
    de_ctx->sig_list = SigInit(de_ctx, sig);
813
    if (de_ctx->sig_list == NULL) {
814
        printf("signature == NULL: ");
815
        goto end;
816
    }
817
818
    SigGroupBuild(de_ctx);
819
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
820
821
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
822
    if (PacketAlertCheck(p, de_ctx->sig_list->id) != 1) {
823
        printf("signature didn't alert: ");
824
        goto end;
825
    }
826
827
    result = 1;
828
end:
829
    DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
830
    DetectEngineCtxFree(de_ctx);
831
    SCReturnInt(result);
832
}
833
834
/**
835
 * \test Test if a packet match a signature given as string
836
 * Hint: Useful for unittests with only one packet and one signature
837
 *
838
 * \param sig pointer to the string signature to test
839
 * \param sid sid number of the signature
840
 *
841
 * \retval return 1 if match
842
 * \retval return 0 if not
843
 */
844
int UTHPacketMatchSig(Packet *p, const char *sig)
845
{
846
    int result = 1;
847
848
    DecodeThreadVars dtv;
849
850
    ThreadVars th_v;
851
    DetectEngineThreadCtx *det_ctx = NULL;
852
853
    memset(&dtv, 0, sizeof(DecodeThreadVars));
854
    memset(&th_v, 0, sizeof(th_v));
855
856
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
857
    if (de_ctx == NULL) {
858
        result=0;
859
        goto end;
860
    }
861
862
    de_ctx->flags |= DE_QUIET;
863
864
    de_ctx->sig_list = SigInit(de_ctx, sig);
865
    if (de_ctx->sig_list == NULL) {
866
        result = 0;
867
        goto end;
868
    }
869
870
    SigGroupBuild(de_ctx);
871
    DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
872
873
    SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
874
    if (PacketAlertCheck(p, de_ctx->sig_list->id) != 1) {
875
        result = 0;
876
        goto end;
877
    }
878
879
end:
880
    if (de_ctx) {
881
  SigGroupCleanup(de_ctx);
882
  SigCleanSignatures(de_ctx);
883
    }
884
885
    if (det_ctx != NULL)
886
        DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
887
    if (de_ctx != NULL)
888
        DetectEngineCtxFree(de_ctx);
889
890
    return result;
891
}
892
893
uint32_t UTHBuildPacketOfFlows(uint32_t start, uint32_t end, uint8_t dir)
894
{
895
    FlowLookupStruct fls;
896
    memset(&fls, 0, sizeof(fls));
897
    ThreadVars tv;
898
    memset(&tv, 0, sizeof(tv));
899
900
    uint32_t i = start;
901
    uint8_t payload[] = "Payload";
902
    for (; i < end; i++) {
903
        Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP);
904
        if (dir == 0) {
905
            p->src.addr_data32[0] = i;
906
            p->dst.addr_data32[0] = i + 1;
907
        } else {
908
            p->src.addr_data32[0] = i + 1;
909
            p->dst.addr_data32[0] = i;
910
        }
911
        FlowHandlePacket(&tv, &fls, p);
912
        if (p->flow != NULL) {
913
            FLOWLOCK_UNLOCK(p->flow);
914
        }
915
916
        /* Now the queues should be updated */
917
        UTHFreePacket(p);
918
    }
919
920
    Flow *f;
921
    while ((f = FlowQueuePrivateGetFromTop(&fls.spare_queue))) {
922
        FlowFree(f);
923
    }
924
    while ((f = FlowQueuePrivateGetFromTop(&fls.work_queue))) {
925
        FlowFree(f);
926
    }
927
928
    return i;
929
}
930
931
/** \brief parser a sig and see if the expected result is correct */
932
int UTHParseSignature(const char *str, bool expect)
933
{
934
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
935
    FAIL_IF_NULL(de_ctx);
936
    de_ctx->flags |= DE_QUIET;
937
938
    Signature *s = DetectEngineAppendSig(de_ctx, str);
939
    if (expect)
940
        FAIL_IF_NULL(s);
941
    else
942
        FAIL_IF_NOT_NULL(s);
943
944
    DetectEngineCtxFree(de_ctx);
945
    PASS;
946
}
947
948
/*
949
 * unittests for the unittest helpers
950
 */
951
952
/**
953
 * \brief CheckUTHTestPacket wrapper to check packets for unittests
954
 */
955
static int CheckUTHTestPacket(Packet *p, uint8_t ipproto)
956
{
957
    uint16_t sport = 41424;
958
    uint16_t dport = 80;
959
    uint8_t payload[] = "Payload";
960
961
    uint8_t len = sizeof(payload);
962
963
    if (p == NULL)
964
        return 0;
965
966
    if (p->payload_len != len)
967
        return 0;
968
969
    if (strncmp((char *)payload, (char *)p->payload, len) != 0)
970
        return 0;
971
972
    if (p->src.family != AF_INET)
973
        return 0;
974
    if (p->dst.family != AF_INET)
975
        return 0;
976
    if (p->proto != ipproto)
977
        return 0;
978
979
    switch(ipproto) {
980
        case IPPROTO_UDP:
981
            if (p->udph == NULL)
982
                return 0;
983
            if (p->udph->uh_sport != sport)
984
                return 0;
985
            if (p->udph->uh_dport != dport)
986
                return 0;
987
        break;
988
        case IPPROTO_TCP:
989
            if (p->tcph == NULL)
990
                return 0;
991
            if (SCNtohs(p->tcph->th_sport) != sport)
992
                return 0;
993
            if (SCNtohs(p->tcph->th_dport) != dport)
994
                return 0;
995
        break;
996
    }
997
    return 1;
998
}
999
1000
#ifdef HAVE_MEMMEM
1001
#include <string.h>
1002
void * UTHmemsearch(const void *big, size_t big_len, const void *little, size_t little_len) {
1003
    return memmem(big, big_len, little, little_len);
1004
}
1005
#else
1006
#include "util-spm-bs.h"
1007
void * UTHmemsearch(const void *big, size_t big_len, const void *little, size_t little_len) {
1008
    return BasicSearch(big, big_len, little, little_len);
1009
}
1010
#endif //HAVE_MEMMEM
1011
1012
/**
1013
 * \brief UTHBuildPacketRealTest01 wrapper to check packets for unittests
1014
 */
1015
static int UTHBuildPacketRealTest01(void)
1016
{
1017
    uint8_t payload[] = "Payload";
1018
1019
    Packet *p = UTHBuildPacketReal(payload, sizeof(payload), IPPROTO_TCP,
1020
                                   "192.168.1.5", "192.168.1.1", 41424, 80);
1021
1022
    int ret = CheckUTHTestPacket(p, IPPROTO_TCP);
1023
    UTHFreePacket(p);
1024
1025
    return ret;
1026
}
1027
1028
/**
1029
 * \brief UTHBuildPacketRealTest02 wrapper to check packets for unittests
1030
 */
1031
static int UTHBuildPacketRealTest02(void)
1032
{
1033
    uint8_t payload[] = "Payload";
1034
1035
    Packet *p = UTHBuildPacketReal(payload, sizeof(payload), IPPROTO_UDP,
1036
                                   "192.168.1.5", "192.168.1.1", 41424, 80);
1037
1038
    int ret = CheckUTHTestPacket(p, IPPROTO_UDP);
1039
    UTHFreePacket(p);
1040
    return ret;
1041
}
1042
1043
/**
1044
 * \brief UTHBuildPacketTest01 wrapper to check packets for unittests
1045
 */
1046
static int UTHBuildPacketTest01(void)
1047
{
1048
    uint8_t payload[] = "Payload";
1049
1050
    Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_TCP);
1051
1052
    int ret = CheckUTHTestPacket(p, IPPROTO_TCP);
1053
    UTHFreePacket(p);
1054
1055
    return ret;
1056
}
1057
1058
/**
1059
 * \brief UTHBuildPacketTest02 wrapper to check packets for unittests
1060
 */
1061
static int UTHBuildPacketTest02(void)
1062
{
1063
    uint8_t payload[] = "Payload";
1064
1065
    Packet *p = UTHBuildPacket(payload, sizeof(payload), IPPROTO_UDP);
1066
1067
    int ret = CheckUTHTestPacket(p, IPPROTO_UDP);
1068
    UTHFreePacket(p);
1069
1070
    return ret;
1071
}
1072
1073
/**
1074
 * \brief UTHBuildPacketOfFlowsTest01 wrapper to check packets for unittests
1075
 */
1076
static int UTHBuildPacketOfFlowsTest01(void)
1077
{
1078
    int result = 0;
1079
1080
    FlowInitConfig(FLOW_QUIET);
1081
    uint32_t flow_spare_q_len = FlowSpareGetPoolSize();
1082
1083
    UTHBuildPacketOfFlows(0, 100, 0);
1084
1085
    if (FlowSpareGetPoolSize() != flow_spare_q_len - 100)
1086
        result = 0;
1087
    else
1088
        result = 1;
1089
    FlowShutdown();
1090
1091
    return result;
1092
}
1093
1094
1095
/**
1096
 * \brief UTHBuildPacketSrcDstTest01 wrapper to check packets for unittests
1097
 */
1098
static int UTHBuildPacketSrcDstTest01(void)
1099
{
1100
    uint8_t payload[] = "Payload";
1101
1102
    Packet *p = UTHBuildPacketSrcDst(payload, sizeof(payload), IPPROTO_TCP,
1103
                                     "192.168.1.5", "192.168.1.1");
1104
1105
    int ret = CheckUTHTestPacket(p, IPPROTO_TCP);
1106
    UTHFreePacket(p);
1107
1108
    return ret;
1109
}
1110
1111
/**
1112
 * \brief UTHBuildPacketSrcDstTest02 wrapper to check packets for unittests
1113
 */
1114
static int UTHBuildPacketSrcDstTest02(void)
1115
{
1116
    uint8_t payload[] = "Payload";
1117
1118
    Packet *p = UTHBuildPacketSrcDst(payload, sizeof(payload), IPPROTO_UDP,
1119
                                     "192.168.1.5", "192.168.1.1");
1120
1121
    int ret = CheckUTHTestPacket(p, IPPROTO_UDP);
1122
    UTHFreePacket(p);
1123
1124
    return ret;
1125
}
1126
1127
/**
1128
 * \brief UTHBuildPacketSrcDstPortsTest01 wrapper to check packets for unittests
1129
 */
1130
static int UTHBuildPacketSrcDstPortsTest01(void)
1131
{
1132
    uint8_t payload[] = "Payload";
1133
1134
    Packet *p = UTHBuildPacketSrcDstPorts(payload, sizeof(payload), IPPROTO_TCP,
1135
                                          41424, 80);
1136
1137
    int ret = CheckUTHTestPacket(p, IPPROTO_TCP);
1138
    UTHFreePacket(p);
1139
1140
    return ret;
1141
}
1142
1143
/**
1144
 * \brief UTHBuildPacketSrcDstPortsTest02 wrapper to check packets for unittests
1145
 */
1146
static int UTHBuildPacketSrcDstPortsTest02(void)
1147
{
1148
    uint8_t payload[] = "Payload";
1149
1150
    Packet *p = UTHBuildPacketSrcDstPorts(payload, sizeof(payload), IPPROTO_UDP,
1151
                                          41424, 80);
1152
1153
    int ret = CheckUTHTestPacket(p, IPPROTO_UDP);
1154
    UTHFreePacket(p);
1155
1156
    return ret;
1157
}
1158
1159
#endif /* UNITTESTS */
1160
1161
void UTHRegisterTests(void)
1162
0
{
1163
#ifdef UNITTESTS
1164
    UtRegisterTest("UTHBuildPacketRealTest01", UTHBuildPacketRealTest01);
1165
    UtRegisterTest("UTHBuildPacketRealTest02", UTHBuildPacketRealTest02);
1166
    UtRegisterTest("UTHBuildPacketTest01", UTHBuildPacketTest01);
1167
    UtRegisterTest("UTHBuildPacketTest02", UTHBuildPacketTest02);
1168
    UtRegisterTest("UTHBuildPacketSrcDstTest01", UTHBuildPacketSrcDstTest01);
1169
    UtRegisterTest("UTHBuildPacketSrcDstTest02", UTHBuildPacketSrcDstTest02);
1170
    UtRegisterTest("UTHBuildPacketSrcDstPortsTest01",
1171
                   UTHBuildPacketSrcDstPortsTest01);
1172
    UtRegisterTest("UTHBuildPacketSrcDstPortsTest02",
1173
                   UTHBuildPacketSrcDstPortsTest02);
1174
    UtRegisterTest("UTHBuildPacketOfFlowsTest01", UTHBuildPacketOfFlowsTest01);
1175
1176
#endif /* UNITTESTS */
1177
0
}
1178