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

OISF / suricata / 23374838686

21 Mar 2026 07:29AM UTC coverage: 59.341% (-20.0%) from 79.315%
23374838686

Pull #15075

github

web-flow
Merge 90b4e834f into 6587e363a
Pull Request #15075: Stack 8001 v16.4

38 of 70 new or added lines in 10 files covered. (54.29%)

34165 existing lines in 563 files now uncovered.

119621 of 201584 relevant lines covered (59.34%)

650666.92 hits per line

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

85.79
/src/flow-util.c
1
/* Copyright (C) 2007-2013 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17

18
/**
19
 * \file
20
 *
21
 * \author Victor Julien <victor@inliniac.net>
22
 *
23
 * Flow utility functions
24
 */
25

26
#include "suricata-common.h"
27
#include "threads.h"
28

29
#include "flow.h"
30
#include "flow-private.h"
31
#include "flow-util.h"
32
#include "flow-callbacks.h"
33
#include "flow-var.h"
34
#include "app-layer.h"
35

36
#include "util-var.h"
37
#include "util-debug.h"
38
#include "util-macset.h"
39
#include "util-flow-rate.h"
40
#include "flow-storage.h"
41

42
#include "detect.h"
43
#include "detect-engine-state.h"
44

45
#include "decode-icmpv4.h"
46

47
#include "util-validate.h"
48

49
/** \brief allocate a flow
50
 *
51
 *  We check against the memuse counter. If it passes that check we increment
52
 *  the counter first, then we try to alloc.
53
 *
54
 *  \retval f the flow or NULL on out of memory
55
 */
56
Flow *FlowAlloc(void)
57
{
63,952✔
58
    Flow *f;
63,952✔
59
    size_t size = sizeof(Flow) + FlowStorageSize();
63,952✔
60

61
    if (!(FLOW_CHECK_MEMCAP(size))) {
63,952✔
62
        return NULL;
×
63
    }
×
64

65
    (void) SC_ATOMIC_ADD(flow_memuse, size);
63,952✔
66

67
    f = SCCalloc(1, size);
63,952✔
68
    if (unlikely(f == NULL)) {
63,952✔
69
        (void)SC_ATOMIC_SUB(flow_memuse, size);
×
70
        return NULL;
×
71
    }
×
72

73
    /* coverity[missing_lock] */
74
    FLOW_INITIALIZE(f);
63,952✔
75
    return f;
63,952✔
76
}
63,952✔
77

78

79
/**
80
 *  \brief cleanup & free the memory of a flow
81
 *
82
 *  \param f flow to clear & destroy
83
 */
84
void FlowFree(Flow *f)
85
{
65,542✔
86
    FLOW_DESTROY(f);
65,542✔
87
    SCFree(f);
65,542✔
88

89
    size_t size = sizeof(Flow) + FlowStorageSize();
65,542✔
90
    (void) SC_ATOMIC_SUB(flow_memuse, size);
65,542✔
91
}
65,542✔
92

93
/**
94
 *  \brief   Function to map the protocol to the defined FLOW_PROTO_* enumeration.
95
 *
96
 *  \param   proto  protocol which is needed to be mapped
97
 */
98

99
uint8_t FlowGetProtoMapping(uint8_t proto)
100
{
42,602,121✔
101
    switch (proto) {
42,602,121✔
102
        case IPPROTO_TCP:
37,786,384✔
103
            return FLOW_PROTO_TCP;
37,786,384✔
104
        case IPPROTO_UDP:
4,810,477✔
105
            return FLOW_PROTO_UDP;
4,810,477✔
106
        case IPPROTO_ICMP:
1,140✔
107
            return FLOW_PROTO_ICMP;
1,140✔
108
        default:
4,120✔
109
            return FLOW_PROTO_DEFAULT;
4,120✔
110
    }
42,602,121✔
111
}
42,602,121✔
112

113
uint8_t FlowGetReverseProtoMapping(uint8_t rproto)
114
{
3,995,946✔
115
    switch (rproto) {
3,995,946✔
116
        case FLOW_PROTO_TCP:
1,331,982✔
117
            return IPPROTO_TCP;
1,331,982✔
118
        case FLOW_PROTO_UDP:
1,331,982✔
119
            return IPPROTO_UDP;
1,331,982✔
120
        case FLOW_PROTO_ICMP:
1,331,982✔
121
            return IPPROTO_ICMP;
1,331,982✔
122
        default:
×
123
            exit(EXIT_FAILURE);
×
124
    }
3,995,946✔
125
}
3,995,946✔
126

127
static inline void FlowSetICMPv4CounterPart(Flow *f)
128
{
532✔
129
    int ctype = ICMPv4GetCounterpart(f->icmp_s.type);
532✔
130
    if (ctype == -1)
532✔
131
        return;
261✔
132

133
    f->icmp_d.type = (uint8_t)ctype;
271✔
134
}
271✔
135

136
static inline void FlowSetICMPv6CounterPart(Flow *f)
137
{
2,050✔
138
    int ctype = ICMPv6GetCounterpart(f->icmp_s.type);
2,050✔
139
    if (ctype == -1)
2,050✔
140
        return;
861✔
141

142
    f->icmp_d.type = (uint8_t)ctype;
1,189✔
143
}
1,189✔
144

145
/* initialize the flow from the first packet
146
 * we see from it. */
147
void FlowInit(ThreadVars *tv, Flow *f, const Packet *p)
148
{
63,336✔
149
    SCEnter();
63,336✔
150
    SCLogDebug("flow %p", f);
63,336✔
151

152
    f->proto = p->proto;
63,336✔
153
    f->recursion_level = p->recursion_level;
63,336✔
154
    memcpy(&f->vlan_id[0], &p->vlan_id[0], sizeof(f->vlan_id));
63,336✔
155
    f->vlan_idx = p->vlan_idx;
63,336✔
156

157
    f->thread_id[0] = (FlowThreadId)tv->id;
63,336✔
158

159
    f->livedev = p->livedev;
63,336✔
160

161
    if (PacketIsIPv4(p)) {
63,336✔
162
        const IPV4Hdr *ip4h = PacketGetIPv4(p);
57,558✔
163
        FLOW_SET_IPV4_SRC_ADDR_FROM_PACKET(ip4h, &f->src);
57,558✔
164
        FLOW_SET_IPV4_DST_ADDR_FROM_PACKET(ip4h, &f->dst);
57,558✔
165
        f->min_ttl_toserver = f->max_ttl_toserver = IPV4_GET_RAW_IPTTL(ip4h);
57,558✔
166
        f->flags |= FLOW_IPV4;
57,558✔
167
    } else if (PacketIsIPv6(p)) {
57,558✔
168
        const IPV6Hdr *ip6h = PacketGetIPv6(p);
5,778✔
169
        FLOW_SET_IPV6_SRC_ADDR_FROM_PACKET(ip6h, &f->src);
5,778✔
170
        FLOW_SET_IPV6_DST_ADDR_FROM_PACKET(ip6h, &f->dst);
5,778✔
171
        f->min_ttl_toserver = f->max_ttl_toserver = IPV6_GET_RAW_HLIM(ip6h);
5,778✔
172
        f->flags |= FLOW_IPV6;
5,778✔
173
    } else {
5,778✔
UNCOV
174
        SCLogDebug("neither IPv4 or IPv6, weird");
×
UNCOV
175
        DEBUG_VALIDATE_BUG_ON(1);
×
UNCOV
176
    }
×
177

178
    if (PacketIsTCP(p) || PacketIsUDP(p)) {
63,336✔
179
        f->sp = p->sp;
60,652✔
180
        f->dp = p->dp;
60,652✔
181
    } else if (PacketIsICMPv4(p)) {
60,652✔
182
        f->icmp_s.type = p->icmp_s.type;
532✔
183
        f->icmp_s.code = p->icmp_s.code;
532✔
184
        FlowSetICMPv4CounterPart(f);
532✔
185
    } else if (PacketIsICMPv6(p)) {
2,152✔
186
        f->icmp_s.type = p->icmp_s.type;
2,050✔
187
        f->icmp_s.code = p->icmp_s.code;
2,050✔
188
        FlowSetICMPv6CounterPart(f);
2,050✔
189
    } else if (PacketIsSCTP(p)) {
2,050✔
190
        f->sp = p->sp;
8✔
191
        f->dp = p->dp;
8✔
192
    } else if (PacketIsESP(p)) {
94✔
193
        f->esp.spi = ESP_GET_SPI(PacketGetESP(p));
71✔
194
    } else {
71✔
195
        /* nothing to do for this IP proto. */
196
        SCLogDebug("no special setup for IP proto %u", p->proto);
23✔
197
    }
23✔
198
    f->startts = p->ts;
63,336✔
199

200
    f->protomap = FlowGetProtoMapping(f->proto);
63,336✔
201
    f->timeout_policy = FlowGetTimeoutPolicy(f);
63,336✔
202

203
    if (MacSetFlowStorageEnabled()) {
63,336✔
UNCOV
204
        DEBUG_VALIDATE_BUG_ON(FlowGetStorageById(f, MacSetGetFlowStorageID()) != NULL);
×
UNCOV
205
        MacSet *ms = MacSetInit(10);
×
UNCOV
206
        FlowSetStorageById(f, MacSetGetFlowStorageID(), ms);
×
UNCOV
207
    }
×
208

209
    if (FlowRateStorageEnabled()) {
63,336✔
UNCOV
210
        DEBUG_VALIDATE_BUG_ON(FlowGetStorageById(f, FlowRateGetStorageID()) != NULL);
×
UNCOV
211
        FlowRateStore *frs = FlowRateStoreInit();
×
UNCOV
212
        FlowSetStorageById(f, FlowRateGetStorageID(), frs);
×
UNCOV
213
    }
×
214

215
    SCFlowRunInitCallbacks(tv, f, p);
63,336✔
216

217
    SCReturn;
63,336✔
218
}
63,336✔
219

220
FlowStorageId g_bypass_info_id = { .id = -1 };
221

222
FlowStorageId GetFlowBypassInfoID(void)
223
{
108,902✔
224
    return g_bypass_info_id;
108,902✔
225
}
108,902✔
226

227
static void FlowBypassFree(void *x)
228
{
×
229
    FlowBypassInfo *fb = (FlowBypassInfo *) x;
×
230

231
    if (fb == NULL)
×
232
        return;
×
233

234
    if (fb->bypass_data && fb->BypassFree) {
×
235
        fb->BypassFree(fb->bypass_data);
×
236
    }
×
237
    SCFree(fb);
×
238
}
×
239

240
void RegisterFlowBypassInfo(void)
241
{
2✔
242
    g_bypass_info_id = FlowStorageRegister("bypass_counters", sizeof(void *),
2✔
243
                                              NULL, FlowBypassFree);
2✔
244
}
2✔
245

246
void FlowEndCountersRegister(ThreadVars *t, FlowEndCounters *fec)
247
{
1✔
248
    for (int i = 0; i < FLOW_STATE_SIZE; i++) {
5✔
249
        const char *name = NULL;
4✔
250
        if (i == FLOW_STATE_NEW) {
4✔
251
            name = "flow.end.state.new";
1✔
252
        } else if (i == FLOW_STATE_ESTABLISHED) {
3✔
253
            name = "flow.end.state.established";
1✔
254
        } else if (i == FLOW_STATE_CLOSED) {
2✔
255
            name = "flow.end.state.closed";
1✔
256
        } else if (i == FLOW_STATE_LOCAL_BYPASSED) {
1✔
257
            name = "flow.end.state.local_bypassed";
1✔
258
#ifdef CAPTURE_OFFLOAD
259
        } else if (i == FLOW_STATE_CAPTURE_BYPASSED) {
260
            name = "flow.end.state.capture_bypassed";
261
#endif
262
        }
1✔
263
        if (name) {
4✔
264
            fec->flow_state[i] = StatsRegisterCounter(name, &t->stats);
4✔
265
        }
4✔
266
    }
4✔
267

268
    for (enum TcpState i = TCP_NONE; i <= TCP_CLOSED; i++) {
13✔
269
        const char *name = NULL;
12✔
270
        switch (i) {
12✔
271
            case TCP_NONE:
1✔
272
                name = "flow.end.tcp_state.none";
1✔
273
                break;
1✔
274
            case TCP_SYN_SENT:
1✔
275
                name = "flow.end.tcp_state.syn_sent";
1✔
276
                break;
1✔
277
            case TCP_SYN_RECV:
1✔
278
                name = "flow.end.tcp_state.syn_recv";
1✔
279
                break;
1✔
280
            case TCP_ESTABLISHED:
1✔
281
                name = "flow.end.tcp_state.established";
1✔
282
                break;
1✔
283
            case TCP_FIN_WAIT1:
1✔
284
                name = "flow.end.tcp_state.fin_wait1";
1✔
285
                break;
1✔
286
            case TCP_FIN_WAIT2:
1✔
287
                name = "flow.end.tcp_state.fin_wait2";
1✔
288
                break;
1✔
289
            case TCP_TIME_WAIT:
1✔
290
                name = "flow.end.tcp_state.time_wait";
1✔
291
                break;
1✔
292
            case TCP_LAST_ACK:
1✔
293
                name = "flow.end.tcp_state.last_ack";
1✔
294
                break;
1✔
295
            case TCP_CLOSE_WAIT:
1✔
296
                name = "flow.end.tcp_state.close_wait";
1✔
297
                break;
1✔
298
            case TCP_CLOSING:
1✔
299
                name = "flow.end.tcp_state.closing";
1✔
300
                break;
1✔
301
            case TCP_CLOSED:
1✔
302
                name = "flow.end.tcp_state.closed";
1✔
303
                break;
1✔
304
        }
12✔
305

306
        fec->flow_tcp_state[i] = StatsRegisterCounter(name, &t->stats);
12✔
307
    }
12✔
308
    fec->flow_tcp_liberal = StatsRegisterCounter("flow.end.tcp_liberal", &t->stats);
1✔
309
}
1✔
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