Coverage Report

Created: 2026-02-14 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata/src/util-flow-rate.c
Line
Count
Source
1
/* Copyright (C) 2025 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 Shivani Bhardwaj <shivani@oisf.net>
22
 *
23
 */
24
25
#include "suricata-common.h"
26
#include "flow-storage.h"
27
#include "flow-util.h"
28
#include "flow-private.h"
29
#include "util-storage.h"
30
#include "conf.h"
31
#include "util-misc.h"
32
#include "util-byte.h"
33
#include "util-flow-rate.h"
34
#include "util-unittest.h"
35
#include "util-unittest-helper.h"
36
37
FlowStorageId g_flowrate_storage_id = { .id = -1 };
38
39
FlowRateConfig flow_rate_config;
40
41
static void FlowRateStoreFree(void *ptr)
42
0
{
43
0
    FlowRateStore *frs = (FlowRateStore *)ptr;
44
0
    size_t total_free = 0;
45
0
    if (frs == NULL)
46
0
        return;
47
48
0
    for (int i = 0; i < 2; i++) {
49
0
        if (frs->dir[i].buf != NULL) {
50
0
            SCFree(frs->dir[i].buf);
51
0
            total_free += (frs->dir[i].size * sizeof(uint64_t));
52
0
        }
53
0
    }
54
55
0
    SCFree(frs);
56
0
    total_free += sizeof(*frs);
57
0
    (void)SC_ATOMIC_SUB(flow_memuse, total_free);
58
0
}
59
60
void FlowRateRegisterFlowStorage(void)
61
38
{
62
38
    SCConfNode *root = SCConfGetNode("flow");
63
38
    if (root == NULL)
64
38
        return;
65
66
38
    bool track_flow = false;
67
0
    track_flow = SCConfNodeLookupChild(root, "rate-tracking") != NULL ? true : false;
68
0
    if (!track_flow)
69
0
        return;
70
71
0
    SCConfNode *node = SCConfGetNode("flow.rate-tracking");
72
0
    const char *val = SCConfNodeLookupChildValue(node, "bytes");
73
0
    if (val == NULL) {
74
0
        FatalError("No value for flow tracking bytes");
75
0
    }
76
0
    uint64_t bytes = 0;
77
0
    if (ParseSizeStringU64(val, &bytes) < 0) {
78
0
        FatalError("Invalid value for flow tracking bytes");
79
0
    }
80
0
    flow_rate_config.bytes = bytes;
81
82
0
    val = SCConfNodeLookupChildValue(node, "interval");
83
0
    if (val == NULL) {
84
0
        FatalError("No value for flow tracking interval");
85
0
    }
86
0
    SCTime_t interval = SCTIME_INITIALIZER;
87
0
    uint16_t secs = 0;
88
0
    if ((StringParseUint16(&secs, 10, 0, val) < 0) || (secs == 0)) {
89
0
        FatalError("Invalid value for flow tracking interval");
90
0
    }
91
0
    flow_rate_config.interval = SCTIME_ADD_SECS(interval, secs);
92
93
0
    g_flowrate_storage_id =
94
0
            FlowStorageRegister("flowrate", sizeof(void *), NULL, FlowRateStoreFree);
95
0
}
96
97
bool FlowRateStorageEnabled(void)
98
8.72M
{
99
8.72M
    return (g_flowrate_storage_id.id != -1);
100
8.72M
}
101
102
FlowRateStore *FlowRateStoreInit(void)
103
0
{
104
0
    FlowRateStore *frs = NULL;
105
0
    size_t total_memuse = 0;
106
0
    size_t expected_memuse = (2 * flow_rate_config.interval.secs * sizeof(uint64_t)) + sizeof(*frs);
107
108
0
    if (!FLOW_CHECK_MEMCAP(expected_memuse)) {
109
0
        return NULL;
110
0
    }
111
0
    frs = SCCalloc(1, sizeof(*frs));
112
0
    if (unlikely(frs == NULL)) {
113
0
        return NULL;
114
0
    }
115
116
0
    total_memuse += sizeof(*frs);
117
0
    for (int i = 0; i < 2; i++) {
118
0
        frs->dir[i].size = (uint16_t)flow_rate_config.interval.secs;
119
0
        frs->dir[i].buf = SCCalloc(frs->dir[i].size, sizeof(uint64_t));
120
0
        if (unlikely(frs->dir[i].buf == NULL)) {
121
0
            FlowRateStoreFree(frs);
122
0
            return NULL;
123
0
        }
124
0
        frs->dir[i].start_ts = SCTIME_INITIALIZER;
125
0
        frs->dir[i].last_ts = SCTIME_INITIALIZER;
126
0
        total_memuse += (frs->dir[i].size * sizeof(uint64_t));
127
0
    }
128
0
    DEBUG_VALIDATE_BUG_ON(total_memuse != expected_memuse);
129
0
    (void)SC_ATOMIC_ADD(flow_memuse, total_memuse);
130
131
0
    return frs;
132
0
}
133
134
FlowStorageId FlowRateGetStorageID(void)
135
0
{
136
0
    return g_flowrate_storage_id;
137
0
}
138
139
static inline void FlowRateClearSumInRange(
140
        FlowRateStore *frs, uint16_t start, uint16_t end, int direction)
141
0
{
142
0
    for (uint16_t i = start; i <= end; i++) {
143
0
        uint64_t byte_count_at_i = frs->dir[direction].buf[i];
144
0
        frs->dir[direction].buf[i] = 0;
145
0
        DEBUG_VALIDATE_BUG_ON(frs->dir[direction].sum < byte_count_at_i);
146
0
        frs->dir[direction].sum -= byte_count_at_i;
147
0
    }
148
0
}
149
150
static inline void FlowRateStoreUpdateCurrentRing(
151
        FlowRateStore *frs, SCTime_t p_ts, uint32_t pkt_len, uint16_t idx, int direction)
152
0
{
153
0
    if (idx > frs->dir[direction].last_idx + 1) {
154
        /* Index is not the same as last or the next so, the ring must be flushed for the items
155
         * in between and sum updated */
156
0
        FlowRateClearSumInRange(frs, frs->dir[direction].last_idx + 1, idx, direction);
157
0
        frs->dir[direction].buf[idx] += pkt_len;
158
        /* Update the total sum */
159
0
        frs->dir[direction].sum += pkt_len;
160
0
    } else if (idx == frs->dir[direction].last_idx) {
161
        /* Index matches the last updated index in the ring buffer */
162
        /* Add to the existing open time interval */
163
0
        frs->dir[direction].buf[idx] += pkt_len;
164
        /* Update the total sum */
165
0
        frs->dir[direction].sum += pkt_len;
166
0
    } else {
167
        /* Index is revisited after a full round of the buffer */
168
0
        uint64_t prev_byte_count = frs->dir[direction].buf[idx];
169
        /* Overwrite the buffer */
170
0
        frs->dir[direction].buf[idx] = pkt_len;
171
0
        DEBUG_VALIDATE_BUG_ON(frs->dir[direction].sum < prev_byte_count);
172
        /* Sum should get rid of previous count on the same index */
173
0
        frs->dir[direction].sum += pkt_len - prev_byte_count;
174
0
        if (idx != frs->dir[direction].last_idx + 1) {
175
            /* Revisited index but not the next to last, so, reset start_ts */
176
0
            frs->dir[direction].start_ts = p_ts;
177
0
        }
178
0
    }
179
0
    frs->dir[direction].last_idx = idx;
180
0
}
181
182
static inline void FlowRateStoreFlushRing(
183
        FlowRateStore *frs, SCTime_t p_ts, uint32_t pkt_len, int direction)
184
0
{
185
0
    memset(frs->dir[direction].buf, 0, frs->dir[direction].size);
186
0
    frs->dir[direction].last_idx = 0;
187
0
    frs->dir[direction].start_ts = p_ts;
188
0
    frs->dir[direction].buf[0] = pkt_len;
189
    /* Overwrite the sum calculated so far */
190
0
    frs->dir[direction].sum = pkt_len;
191
0
}
192
193
void FlowRateStoreUpdate(FlowRateStore *frs, SCTime_t p_ts, uint32_t pkt_len, int direction)
194
0
{
195
0
    if (frs->dir[direction].last_ts.secs == 0) {
196
        /* Should only happen when the ring is first used */
197
0
        DEBUG_VALIDATE_BUG_ON(frs->dir[direction].sum > 0);
198
        /* Initialize last_ts and start_ts with the first packet's timestamp */
199
0
        frs->dir[direction].last_ts = p_ts;
200
0
        frs->dir[direction].start_ts = p_ts;
201
0
    }
202
203
0
    SCTime_t start_ts = frs->dir[direction].start_ts;
204
0
    uint16_t idx = (p_ts.secs - start_ts.secs) % frs->dir[direction].size;
205
    /* Update start_ts in case of initiating the revisit of buffer */
206
0
    if ((frs->dir[direction].last_idx == frs->dir[direction].size - 1) &&
207
0
            (frs->dir[direction].last_idx != idx)) {
208
0
        start_ts = p_ts;
209
0
        if (idx != 0) {
210
            /* Update the sum */
211
0
            FlowRateClearSumInRange(frs, 0, idx, direction);
212
            /* Consider current packet a new start of the ring */
213
0
            idx = 0;
214
0
        }
215
0
    }
216
    /* If the packet has come in the last open interval of time */
217
0
    if (p_ts.secs - start_ts.secs < frs->dir[direction].size) {
218
0
        FlowRateStoreUpdateCurrentRing(frs, p_ts, pkt_len, idx, direction);
219
0
    } else {
220
        /* Packet arrived after one or more rounds of the entire buffer */
221
        /* Flush the entire buffer */
222
0
        FlowRateStoreFlushRing(frs, p_ts, pkt_len, direction);
223
0
    }
224
    /* In any case, update the last seen timestamp */
225
0
    frs->dir[direction].last_ts = p_ts;
226
0
}
227
228
bool FlowRateIsExceeding(FlowRateStore *frs, int direction)
229
0
{
230
0
    if (frs->dir[direction].sum >= flow_rate_config.bytes) {
231
0
        return true;
232
0
    }
233
0
    return false;
234
0
}
235
236
#ifdef UNITTESTS
237
238
/* Test to check update of the same buffer item */
239
static int FlowRateTest01(void)
240
{
241
    SC_ATOMIC_SET(flow_config.memcap, 10000);
242
    flow_rate_config.bytes = 100;
243
    flow_rate_config.interval = (SCTime_t){ .secs = 10, .usecs = 0 };
244
    FlowRateStore *frs = FlowRateStoreInit();
245
    FAIL_IF_NULL(frs);
246
    for (int i = 0; i < 2; i++) {
247
        FAIL_IF(frs->dir[i].size != 10);
248
        FAIL_IF(frs->dir[i].sum != 0);
249
    }
250
    Packet *p1 = UTHBuildPacket((uint8_t *)"blahblah", 8, IPPROTO_TCP);
251
    FlowRateStoreUpdate(frs, p1->ts, GET_PKT_LEN(p1), TOSERVER);
252
    /* Total length of packet is 48 */
253
    FAIL_IF(frs->dir[0].sum != 48);
254
    FAIL_IF(frs->dir[0].last_ts.secs != p1->ts.secs);
255
    FAIL_IF(frs->dir[0].buf[0] != 48);
256
257
    Packet *p2 = UTHBuildPacket((uint8_t *)"DATA", 4, IPPROTO_TCP);
258
    FlowRateStoreUpdate(frs, p2->ts, GET_PKT_LEN(p2), TOSERVER);
259
    /* Total length of packet is 44 */
260
    FAIL_IF(frs->dir[0].sum != 92);
261
    FAIL_IF(frs->dir[0].last_ts.secs != p2->ts.secs);
262
    FAIL_IF(frs->dir[0].buf[0] != 92);
263
264
    Packet *p3 = UTHBuildPacket((uint8_t *)"ABababa", 7, IPPROTO_TCP);
265
    FlowRateStoreUpdate(frs, p3->ts, GET_PKT_LEN(p3), TOSERVER);
266
    /* Total length of packet is 47 */
267
    FAIL_IF(frs->dir[0].sum != 139);
268
    FAIL_IF(frs->dir[0].last_ts.secs != p3->ts.secs);
269
    FAIL_IF(frs->dir[0].buf[0] != 139);
270
271
    UTHFreePacket(p1);
272
    UTHFreePacket(p2);
273
    UTHFreePacket(p3);
274
    FlowRateStoreFree(frs);
275
    PASS;
276
}
277
278
/* Test to check update of all buffer items */
279
static int FlowRateTest02(void)
280
{
281
    SC_ATOMIC_SET(flow_config.memcap, 10000);
282
    flow_rate_config.bytes = 200;
283
    flow_rate_config.interval = (SCTime_t){ .secs = 4, .usecs = 0 };
284
    FlowRateStore *frs = FlowRateStoreInit();
285
    FAIL_IF_NULL(frs);
286
    for (int i = 0; i < 2; i++) {
287
        FAIL_IF(frs->dir[i].size != 4);
288
        FAIL_IF(frs->dir[i].sum != 0);
289
    }
290
    Packet *p1 = UTHBuildPacket((uint8_t *)"blahblah", 8, IPPROTO_TCP);
291
    FlowRateStoreUpdate(frs, p1->ts, GET_PKT_LEN(p1), TOSERVER);
292
    /* Total length of packet is 48 */
293
    FAIL_IF(frs->dir[0].sum != 48);
294
    FAIL_IF(frs->dir[0].last_ts.secs != p1->ts.secs);
295
    FAIL_IF(frs->dir[0].buf[0] != 48);
296
297
    Packet *p2 = UTHBuildPacket((uint8_t *)"DATA", 4, IPPROTO_TCP);
298
    p2->ts.secs = p1->ts.secs + 1;
299
    FlowRateStoreUpdate(frs, p2->ts, GET_PKT_LEN(p2), TOSERVER);
300
    /* Total length of packet is 44 */
301
    FAIL_IF(frs->dir[0].sum != 92);
302
    FAIL_IF(frs->dir[0].last_ts.secs != p2->ts.secs);
303
    FAIL_IF(frs->dir[0].buf[1] != 44);
304
305
    Packet *p3 = UTHBuildPacket((uint8_t *)"ABababa", 7, IPPROTO_TCP);
306
    p3->ts.secs = p1->ts.secs + 2;
307
    FlowRateStoreUpdate(frs, p3->ts, GET_PKT_LEN(p3), TOSERVER);
308
    /* Total length of packet is 47 */
309
    FAIL_IF(frs->dir[0].sum != 139);
310
    FAIL_IF(frs->dir[0].last_ts.secs != p3->ts.secs);
311
    FAIL_IF(frs->dir[0].buf[2] != 47);
312
313
    Packet *p4 = UTHBuildPacket((uint8_t *)"yoohoo", 6, IPPROTO_TCP);
314
    p4->ts.secs = p1->ts.secs + 3;
315
    FlowRateStoreUpdate(frs, p4->ts, GET_PKT_LEN(p4), TOSERVER);
316
    /* Total length of packet is 46 */
317
    FAIL_IF(frs->dir[0].sum != 185);
318
    FAIL_IF(frs->dir[0].last_ts.secs != p4->ts.secs);
319
    FAIL_IF(frs->dir[0].buf[3] != 46);
320
321
    UTHFreePacket(p1);
322
    UTHFreePacket(p2);
323
    UTHFreePacket(p3);
324
    UTHFreePacket(p4);
325
    FlowRateStoreFree(frs);
326
    PASS;
327
}
328
329
/* Test to check update of wrapping around ring buffer */
330
static int FlowRateTest03(void)
331
{
332
    SC_ATOMIC_SET(flow_config.memcap, 10000);
333
    flow_rate_config.bytes = 200;
334
    flow_rate_config.interval = (SCTime_t){ .secs = 4, .usecs = 0 };
335
    FlowRateStore *frs = FlowRateStoreInit();
336
    FAIL_IF_NULL(frs);
337
    for (int i = 0; i < 2; i++) {
338
        FAIL_IF(frs->dir[i].size != 4);
339
        FAIL_IF(frs->dir[i].sum != 0);
340
    }
341
    Packet *p1 = UTHBuildPacket((uint8_t *)"blahblah", 8, IPPROTO_TCP);
342
    FlowRateStoreUpdate(frs, p1->ts, GET_PKT_LEN(p1), TOSERVER);
343
    /* Total length of packet is 48 */
344
    FAIL_IF(frs->dir[0].sum != 48);
345
    FAIL_IF(frs->dir[0].last_ts.secs != p1->ts.secs);
346
    FAIL_IF(frs->dir[0].buf[0] != 48);
347
    FAIL_IF(frs->dir[0].start_ts.secs != p1->ts.secs);
348
349
    Packet *p2 = UTHBuildPacket((uint8_t *)"DATA", 4, IPPROTO_TCP);
350
    p2->ts.secs = p1->ts.secs + 1;
351
    FlowRateStoreUpdate(frs, p2->ts, GET_PKT_LEN(p2), TOSERVER);
352
    /* Total length of packet is 44 */
353
    FAIL_IF(frs->dir[0].sum != 92);
354
    FAIL_IF(frs->dir[0].last_ts.secs != p2->ts.secs);
355
    FAIL_IF(frs->dir[0].buf[1] != 44);
356
    FAIL_IF(frs->dir[0].start_ts.secs != p1->ts.secs);
357
358
    Packet *p3 = UTHBuildPacket((uint8_t *)"ABababa", 7, IPPROTO_TCP);
359
    p3->ts.secs = p1->ts.secs + 2;
360
    FlowRateStoreUpdate(frs, p3->ts, GET_PKT_LEN(p3), TOSERVER);
361
    /* Total length of packet is 47 */
362
    FAIL_IF(frs->dir[0].sum != 139);
363
    FAIL_IF(frs->dir[0].last_ts.secs != p3->ts.secs);
364
    FAIL_IF(frs->dir[0].buf[2] != 47);
365
    FAIL_IF(frs->dir[0].start_ts.secs != p1->ts.secs);
366
367
    Packet *p4 = UTHBuildPacket((uint8_t *)"yoohoo", 6, IPPROTO_TCP);
368
    p4->ts.secs = p1->ts.secs + 3;
369
    FlowRateStoreUpdate(frs, p4->ts, GET_PKT_LEN(p4), TOSERVER);
370
    /* Total length of packet is 46 */
371
    FAIL_IF(frs->dir[0].sum != 185);
372
    FAIL_IF(frs->dir[0].last_ts.secs != p4->ts.secs);
373
    FAIL_IF(frs->dir[0].buf[3] != 46);
374
    FAIL_IF(frs->dir[0].start_ts.secs != p1->ts.secs);
375
376
    Packet *p5 = UTHBuildPacket((uint8_t *)"nmn", 3, IPPROTO_TCP);
377
    p5->ts.secs = p1->ts.secs + 4;
378
    FlowRateStoreUpdate(frs, p5->ts, GET_PKT_LEN(p5), TOSERVER);
379
    /* Total length of packet is 43 */
380
    FAIL_IF(frs->dir[0].sum != 180);
381
    FAIL_IF(frs->dir[0].last_ts.secs != p5->ts.secs);
382
    FAIL_IF(frs->dir[0].start_ts.secs != p5->ts.secs);
383
    FAIL_IF(frs->dir[0].buf[0] != 43);
384
385
    Packet *p6 = UTHBuildPacket((uint8_t *)"meerkat", 7, IPPROTO_TCP);
386
    p6->ts.secs = p1->ts.secs + 5;
387
    FlowRateStoreUpdate(frs, p6->ts, GET_PKT_LEN(p6), TOSERVER);
388
    /* Total length of packet is 47 */
389
    FAIL_IF(frs->dir[0].sum != 183);
390
    FAIL_IF(frs->dir[0].last_ts.secs != p6->ts.secs);
391
    FAIL_IF(frs->dir[0].start_ts.secs != p5->ts.secs);
392
    FAIL_IF(frs->dir[0].buf[1] != 47);
393
394
    UTHFreePacket(p1);
395
    UTHFreePacket(p2);
396
    UTHFreePacket(p3);
397
    UTHFreePacket(p4);
398
    UTHFreePacket(p5);
399
    UTHFreePacket(p6);
400
    FlowRateStoreFree(frs);
401
    PASS;
402
}
403
404
/* Test to check update of buffer if new pkt comes out of the window */
405
static int FlowRateTest04(void)
406
{
407
    SC_ATOMIC_SET(flow_config.memcap, 10000);
408
    flow_rate_config.bytes = 200;
409
    flow_rate_config.interval = (SCTime_t){ .secs = 4, .usecs = 0 };
410
    FlowRateStore *frs = FlowRateStoreInit();
411
    FAIL_IF_NULL(frs);
412
    for (int i = 0; i < 2; i++) {
413
        FAIL_IF(frs->dir[i].size != 4);
414
        FAIL_IF(frs->dir[i].sum != 0);
415
    }
416
    Packet *p1 = UTHBuildPacket((uint8_t *)"blahblah", 8, IPPROTO_TCP);
417
    FlowRateStoreUpdate(frs, p1->ts, GET_PKT_LEN(p1), TOSERVER);
418
    /* Total length of packet is 48 */
419
    FAIL_IF(frs->dir[0].sum != 48);
420
    FAIL_IF(frs->dir[0].last_ts.secs != p1->ts.secs);
421
    FAIL_IF(frs->dir[0].buf[0] != 48);
422
    FAIL_IF(frs->dir[0].start_ts.secs != p1->ts.secs);
423
424
    Packet *p2 = UTHBuildPacket((uint8_t *)"DATA", 4, IPPROTO_TCP);
425
    p2->ts.secs = p1->ts.secs + 60;
426
    FlowRateStoreUpdate(frs, p2->ts, GET_PKT_LEN(p2), TOSERVER);
427
    /* Total length of packet is 44 */
428
    FAIL_IF(frs->dir[0].sum != 44);
429
    FAIL_IF(frs->dir[0].last_ts.secs != p2->ts.secs);
430
    FAIL_IF(frs->dir[0].buf[0] != 44);
431
    FAIL_IF(frs->dir[0].start_ts.secs != p2->ts.secs);
432
433
    UTHFreePacket(p1);
434
    UTHFreePacket(p2);
435
    FlowRateStoreFree(frs);
436
    PASS;
437
}
438
439
/* Test to check update of wrapping around ring buffer when the packet
440
 * out of the window but also does not fall on the first index of the ring */
441
static int FlowRateTest05(void)
442
{
443
    SC_ATOMIC_SET(flow_config.memcap, 10000);
444
    flow_rate_config.bytes = 200;
445
    flow_rate_config.interval = (SCTime_t){ .secs = 4, .usecs = 0 };
446
    FlowRateStore *frs = FlowRateStoreInit();
447
    FAIL_IF_NULL(frs);
448
    for (int i = 0; i < 2; i++) {
449
        FAIL_IF(frs->dir[i].size != 4);
450
        FAIL_IF(frs->dir[i].sum != 0);
451
    }
452
    Packet *p1 = UTHBuildPacket((uint8_t *)"blahblah", 8, IPPROTO_TCP);
453
    FlowRateStoreUpdate(frs, p1->ts, GET_PKT_LEN(p1), TOSERVER);
454
    /* Total length of packet is 48 */
455
    FAIL_IF(frs->dir[0].sum != 48);
456
    FAIL_IF(frs->dir[0].last_ts.secs != p1->ts.secs);
457
    FAIL_IF(frs->dir[0].buf[0] != 48);
458
    FAIL_IF(frs->dir[0].start_ts.secs != p1->ts.secs);
459
460
    Packet *p2 = UTHBuildPacket((uint8_t *)"DATA", 4, IPPROTO_TCP);
461
    p2->ts.secs = p1->ts.secs + 1;
462
    FlowRateStoreUpdate(frs, p2->ts, GET_PKT_LEN(p2), TOSERVER);
463
    /* Total length of packet is 44 */
464
    FAIL_IF(frs->dir[0].sum != 92);
465
    FAIL_IF(frs->dir[0].last_ts.secs != p2->ts.secs);
466
    FAIL_IF(frs->dir[0].buf[1] != 44);
467
    FAIL_IF(frs->dir[0].start_ts.secs != p1->ts.secs);
468
469
    Packet *p3 = UTHBuildPacket((uint8_t *)"ABababa", 7, IPPROTO_TCP);
470
    p3->ts.secs = p1->ts.secs + 2;
471
    FlowRateStoreUpdate(frs, p3->ts, GET_PKT_LEN(p3), TOSERVER);
472
    /* Total length of packet is 47 */
473
    FAIL_IF(frs->dir[0].sum != 139);
474
    FAIL_IF(frs->dir[0].last_ts.secs != p3->ts.secs);
475
    FAIL_IF(frs->dir[0].buf[2] != 47);
476
    FAIL_IF(frs->dir[0].start_ts.secs != p1->ts.secs);
477
478
    Packet *p4 = UTHBuildPacket((uint8_t *)"yoohoo", 6, IPPROTO_TCP);
479
    p4->ts.secs = p1->ts.secs + 3;
480
    FlowRateStoreUpdate(frs, p4->ts, GET_PKT_LEN(p4), TOSERVER);
481
    /* Total length of packet is 46 */
482
    FAIL_IF(frs->dir[0].sum != 185);
483
    FAIL_IF(frs->dir[0].last_ts.secs != p4->ts.secs);
484
    FAIL_IF(frs->dir[0].buf[3] != 46);
485
    FAIL_IF(frs->dir[0].start_ts.secs != p1->ts.secs);
486
487
    Packet *p5 = UTHBuildPacket((uint8_t *)"nmn", 3, IPPROTO_TCP);
488
    p5->ts.secs = p1->ts.secs + 6;
489
    FlowRateStoreUpdate(frs, p5->ts, GET_PKT_LEN(p5), TOSERVER);
490
    /* Total length of packet is 43 */
491
    FAIL_IF(frs->dir[0].sum != 89);
492
    FAIL_IF(frs->dir[0].last_ts.secs != p5->ts.secs);
493
    FAIL_IF(frs->dir[0].start_ts.secs != p5->ts.secs);
494
    FAIL_IF(frs->dir[0].buf[0] != 43);
495
496
    UTHFreePacket(p1);
497
    UTHFreePacket(p2);
498
    UTHFreePacket(p3);
499
    UTHFreePacket(p4);
500
    UTHFreePacket(p5);
501
    FlowRateStoreFree(frs);
502
    PASS;
503
}
504
505
/* Test to check sum when packet is within the window but is coming after a gap */
506
static int FlowRateTest06(void)
507
{
508
    SC_ATOMIC_SET(flow_config.memcap, 10000);
509
    flow_rate_config.bytes = 200;
510
    flow_rate_config.interval = (SCTime_t){ .secs = 4, .usecs = 0 };
511
    FlowRateStore *frs = FlowRateStoreInit();
512
    FAIL_IF_NULL(frs);
513
    for (int i = 0; i < 2; i++) {
514
        FAIL_IF(frs->dir[i].size != 4);
515
        FAIL_IF(frs->dir[i].sum != 0);
516
    }
517
    Packet *p1 = UTHBuildPacket((uint8_t *)"blahblah", 8, IPPROTO_TCP);
518
    FlowRateStoreUpdate(frs, p1->ts, GET_PKT_LEN(p1), TOSERVER);
519
    /* Total length of packet is 48 */
520
    FAIL_IF(frs->dir[0].sum != 48);
521
    FAIL_IF(frs->dir[0].last_ts.secs != p1->ts.secs);
522
    FAIL_IF(frs->dir[0].buf[0] != 48);
523
    FAIL_IF(frs->dir[0].start_ts.secs != p1->ts.secs);
524
525
    Packet *p2 = UTHBuildPacket((uint8_t *)"DATA", 4, IPPROTO_TCP);
526
    p2->ts.secs = p1->ts.secs + 1;
527
    FlowRateStoreUpdate(frs, p2->ts, GET_PKT_LEN(p2), TOSERVER);
528
    /* Total length of packet is 44 */
529
    FAIL_IF(frs->dir[0].sum != 92);
530
    FAIL_IF(frs->dir[0].last_ts.secs != p2->ts.secs);
531
    FAIL_IF(frs->dir[0].buf[1] != 44);
532
    FAIL_IF(frs->dir[0].start_ts.secs != p1->ts.secs);
533
534
    Packet *p3 = UTHBuildPacket((uint8_t *)"ABababa", 7, IPPROTO_TCP);
535
    p3->ts.secs = p1->ts.secs + 2;
536
    FlowRateStoreUpdate(frs, p3->ts, GET_PKT_LEN(p3), TOSERVER);
537
    /* Total length of packet is 47 */
538
    FAIL_IF(frs->dir[0].sum != 139);
539
    FAIL_IF(frs->dir[0].last_ts.secs != p3->ts.secs);
540
    FAIL_IF(frs->dir[0].buf[2] != 47);
541
    FAIL_IF(frs->dir[0].start_ts.secs != p1->ts.secs);
542
543
    Packet *p4 = UTHBuildPacket((uint8_t *)"yoohoo", 6, IPPROTO_TCP);
544
    p4->ts.secs = p1->ts.secs + 3;
545
    FlowRateStoreUpdate(frs, p4->ts, GET_PKT_LEN(p4), TOSERVER);
546
    /* Total length of packet is 46 */
547
    FAIL_IF(frs->dir[0].sum != 185);
548
    FAIL_IF(frs->dir[0].last_ts.secs != p4->ts.secs);
549
    FAIL_IF(frs->dir[0].buf[3] != 46);
550
    FAIL_IF(frs->dir[0].start_ts.secs != p1->ts.secs);
551
552
    Packet *p5 = UTHBuildPacket((uint8_t *)"nmn", 3, IPPROTO_TCP);
553
    p5->ts.secs = p1->ts.secs + 4;
554
    FlowRateStoreUpdate(frs, p5->ts, GET_PKT_LEN(p5), TOSERVER);
555
    /* Total length of packet is 43 */
556
    FAIL_IF(frs->dir[0].sum != 180);
557
    FAIL_IF(frs->dir[0].last_ts.secs != p5->ts.secs);
558
    FAIL_IF(frs->dir[0].start_ts.secs != p5->ts.secs);
559
    FAIL_IF(frs->dir[0].buf[0] != 43);
560
561
    Packet *p6 = UTHBuildPacket((uint8_t *)"suricata", 8, IPPROTO_TCP);
562
    p6->ts.secs = p1->ts.secs + 7;
563
    FlowRateStoreUpdate(frs, p6->ts, GET_PKT_LEN(p6), TOSERVER);
564
    /* Total length of packet is 48 */
565
    FAIL_IF(frs->dir[0].sum != 91);
566
    FAIL_IF(frs->dir[0].last_ts.secs != p6->ts.secs);
567
    FAIL_IF(frs->dir[0].start_ts.secs != p5->ts.secs);
568
    FAIL_IF(frs->dir[0].buf[0] != 43);
569
    FAIL_IF(frs->dir[0].buf[1] != 0);
570
    FAIL_IF(frs->dir[0].buf[2] != 0);
571
    FAIL_IF(frs->dir[0].buf[3] != 48);
572
573
    UTHFreePacket(p1);
574
    UTHFreePacket(p2);
575
    UTHFreePacket(p3);
576
    UTHFreePacket(p4);
577
    UTHFreePacket(p5);
578
    UTHFreePacket(p6);
579
    FlowRateStoreFree(frs);
580
    PASS;
581
}
582
583
/* Test to check sum when two packets are back to back within the window but are coming after a gap
584
 */
585
static int FlowRateTest07(void)
586
{
587
    SC_ATOMIC_SET(flow_config.memcap, 10000);
588
    flow_rate_config.bytes = 200;
589
    flow_rate_config.interval = (SCTime_t){ .secs = 4, .usecs = 0 };
590
    FlowRateStore *frs = FlowRateStoreInit();
591
    FAIL_IF_NULL(frs);
592
    for (int i = 0; i < 2; i++) {
593
        FAIL_IF(frs->dir[i].size != 4);
594
        FAIL_IF(frs->dir[i].sum != 0);
595
    }
596
    Packet *p1 = UTHBuildPacket((uint8_t *)"blahblah", 8, IPPROTO_TCP);
597
    FlowRateStoreUpdate(frs, p1->ts, GET_PKT_LEN(p1), TOSERVER);
598
    /* Total length of packet is 48 */
599
    FAIL_IF(frs->dir[0].sum != 48);
600
    FAIL_IF(frs->dir[0].last_ts.secs != p1->ts.secs);
601
    FAIL_IF(frs->dir[0].buf[0] != 48);
602
    FAIL_IF(frs->dir[0].start_ts.secs != p1->ts.secs);
603
604
    Packet *p2 = UTHBuildPacket((uint8_t *)"DATA", 4, IPPROTO_TCP);
605
    p2->ts.secs = p1->ts.secs + 1;
606
    FlowRateStoreUpdate(frs, p2->ts, GET_PKT_LEN(p2), TOSERVER);
607
    /* Total length of packet is 44 */
608
    FAIL_IF(frs->dir[0].sum != 92);
609
    FAIL_IF(frs->dir[0].last_ts.secs != p2->ts.secs);
610
    FAIL_IF(frs->dir[0].buf[1] != 44);
611
    FAIL_IF(frs->dir[0].start_ts.secs != p1->ts.secs);
612
613
    Packet *p3 = UTHBuildPacket((uint8_t *)"ABababa", 7, IPPROTO_TCP);
614
    p3->ts.secs = p1->ts.secs + 2;
615
    FlowRateStoreUpdate(frs, p3->ts, GET_PKT_LEN(p3), TOSERVER);
616
    /* Total length of packet is 47 */
617
    FAIL_IF(frs->dir[0].sum != 139);
618
    FAIL_IF(frs->dir[0].last_ts.secs != p3->ts.secs);
619
    FAIL_IF(frs->dir[0].buf[2] != 47);
620
    FAIL_IF(frs->dir[0].start_ts.secs != p1->ts.secs);
621
622
    Packet *p4 = UTHBuildPacket((uint8_t *)"yoohoo", 6, IPPROTO_TCP);
623
    p4->ts.secs = p1->ts.secs + 3;
624
    FlowRateStoreUpdate(frs, p4->ts, GET_PKT_LEN(p4), TOSERVER);
625
    /* Total length of packet is 46 */
626
    FAIL_IF(frs->dir[0].sum != 185);
627
    FAIL_IF(frs->dir[0].last_ts.secs != p4->ts.secs);
628
    FAIL_IF(frs->dir[0].buf[3] != 46);
629
    FAIL_IF(frs->dir[0].start_ts.secs != p1->ts.secs);
630
631
    Packet *p5 = UTHBuildPacket((uint8_t *)"nmn", 3, IPPROTO_TCP);
632
    p5->ts.secs = p1->ts.secs + 5;
633
    FlowRateStoreUpdate(frs, p5->ts, GET_PKT_LEN(p5), TOSERVER);
634
    /* Total length of packet is 43 */
635
    FAIL_IF(frs->dir[0].sum != 136);
636
    FAIL_IF(frs->dir[0].last_ts.secs != p5->ts.secs);
637
    FAIL_IF(frs->dir[0].start_ts.secs != p5->ts.secs);
638
    FAIL_IF(frs->dir[0].buf[0] != 43);
639
640
    Packet *p6 = UTHBuildPacket((uint8_t *)"suricata", 8, IPPROTO_TCP);
641
    p6->ts.secs = p1->ts.secs + 8;
642
    FlowRateStoreUpdate(frs, p6->ts, GET_PKT_LEN(p6), TOSERVER);
643
    /* Total length of packet is 48 */
644
    FAIL_IF(frs->dir[0].sum != 91);
645
    FAIL_IF(frs->dir[0].last_ts.secs != p6->ts.secs);
646
    FAIL_IF(frs->dir[0].start_ts.secs != p5->ts.secs);
647
    FAIL_IF(frs->dir[0].buf[0] != 43);
648
    FAIL_IF(frs->dir[0].buf[1] != 0);
649
    FAIL_IF(frs->dir[0].buf[2] != 0);
650
    FAIL_IF(frs->dir[0].buf[3] != 48);
651
652
    UTHFreePacket(p1);
653
    UTHFreePacket(p2);
654
    UTHFreePacket(p3);
655
    UTHFreePacket(p4);
656
    UTHFreePacket(p5);
657
    UTHFreePacket(p6);
658
    FlowRateStoreFree(frs);
659
    PASS;
660
}
661
662
void FlowRateRegisterTests(void)
663
{
664
    UtRegisterTest("FlowRateTest01", FlowRateTest01);
665
    UtRegisterTest("FlowRateTest02", FlowRateTest02);
666
    UtRegisterTest("FlowRateTest03", FlowRateTest03);
667
    UtRegisterTest("FlowRateTest04", FlowRateTest04);
668
    UtRegisterTest("FlowRateTest05", FlowRateTest05);
669
    UtRegisterTest("FlowRateTest06", FlowRateTest06);
670
    UtRegisterTest("FlowRateTest07", FlowRateTest07);
671
}
672
#endif