Coverage Report

Created: 2026-11-12 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/src/flow-util.c
Line
Count
Source
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
481k
{
58
481k
    Flow *f;
59
481k
    size_t size = sizeof(Flow) + FlowStorageSize();
60
61
481k
    if (!(FLOW_CHECK_MEMCAP(size))) {
62
0
        return NULL;
63
0
    }
64
65
481k
    (void) SC_ATOMIC_ADD(flow_memuse, size);
66
67
481k
    f = SCCalloc(1, size);
68
481k
    if (unlikely(f == NULL)) {
69
0
        (void)SC_ATOMIC_SUB(flow_memuse, size);
70
0
        return NULL;
71
0
    }
72
73
    /* coverity[missing_lock] */
74
481k
    FLOW_INITIALIZE(f);
75
481k
    return f;
76
481k
}
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
437k
{
86
437k
    FLOW_DESTROY(f);
87
437k
    SCFree(f);
88
89
437k
    size_t size = sizeof(Flow) + FlowStorageSize();
90
437k
    (void) SC_ATOMIC_SUB(flow_memuse, size);
91
437k
}
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
3.33G
{
101
3.33G
    switch (proto) {
102
2.43G
        case IPPROTO_TCP:
103
2.43G
            return FLOW_PROTO_TCP;
104
898M
        case IPPROTO_UDP:
105
898M
            return FLOW_PROTO_UDP;
106
10.8k
        case IPPROTO_ICMP:
107
10.8k
            return FLOW_PROTO_ICMP;
108
41.9k
        default:
109
41.9k
            return FLOW_PROTO_DEFAULT;
110
3.33G
    }
111
3.33G
}
112
113
uint8_t FlowGetReverseProtoMapping(uint8_t rproto)
114
4.22M
{
115
4.22M
    switch (rproto) {
116
1.40M
        case FLOW_PROTO_TCP:
117
1.40M
            return IPPROTO_TCP;
118
1.40M
        case FLOW_PROTO_UDP:
119
1.40M
            return IPPROTO_UDP;
120
1.40M
        case FLOW_PROTO_ICMP:
121
1.40M
            return IPPROTO_ICMP;
122
0
        default:
123
0
            exit(EXIT_FAILURE);
124
4.22M
    }
125
4.22M
}
126
127
static inline void FlowSetICMPv4CounterPart(Flow *f)
128
5.57k
{
129
5.57k
    int ctype = ICMPv4GetCounterpart(f->icmp_s.type);
130
5.57k
    if (ctype == -1)
131
2.51k
        return;
132
133
3.06k
    f->icmp_d.type = (uint8_t)ctype;
134
3.06k
}
135
136
static inline void FlowSetICMPv6CounterPart(Flow *f)
137
17.9k
{
138
17.9k
    int ctype = ICMPv6GetCounterpart(f->icmp_s.type);
139
17.9k
    if (ctype == -1)
140
11.1k
        return;
141
142
6.75k
    f->icmp_d.type = (uint8_t)ctype;
143
6.75k
}
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
485k
{
149
485k
    SCEnter();
150
485k
    SCLogDebug("flow %p", f);
151
152
485k
    f->proto = p->proto;
153
485k
    f->recursion_level = p->recursion_level;
154
485k
    memcpy(&f->vlan_id[0], &p->vlan_id[0], sizeof(f->vlan_id));
155
485k
    f->vlan_idx = p->vlan_idx;
156
157
485k
    f->thread_id[0] = (FlowThreadId)tv->id;
158
159
485k
    f->livedev = p->livedev;
160
161
485k
    if (PacketIsIPv4(p)) {
162
411k
        const IPV4Hdr *ip4h = PacketGetIPv4(p);
163
411k
        FLOW_SET_IPV4_SRC_ADDR_FROM_PACKET(ip4h, &f->src);
164
411k
        FLOW_SET_IPV4_DST_ADDR_FROM_PACKET(ip4h, &f->dst);
165
411k
        f->min_ttl_toserver = f->max_ttl_toserver = IPV4_GET_RAW_IPTTL(ip4h);
166
411k
        f->flags |= FLOW_IPV4;
167
411k
    } else if (PacketIsIPv6(p)) {
168
74.4k
        const IPV6Hdr *ip6h = PacketGetIPv6(p);
169
74.4k
        FLOW_SET_IPV6_SRC_ADDR_FROM_PACKET(ip6h, &f->src);
170
74.4k
        FLOW_SET_IPV6_DST_ADDR_FROM_PACKET(ip6h, &f->dst);
171
74.4k
        f->min_ttl_toserver = f->max_ttl_toserver = IPV6_GET_RAW_HLIM(ip6h);
172
74.4k
        f->flags |= FLOW_IPV6;
173
74.4k
    } else {
174
0
        SCLogDebug("neither IPv4 or IPv6, weird");
175
0
        DEBUG_VALIDATE_BUG_ON(1);
176
0
    }
177
178
485k
    if (PacketIsTCP(p) || PacketIsUDP(p)) {
179
459k
        f->sp = p->sp;
180
459k
        f->dp = p->dp;
181
459k
    } else if (PacketIsICMPv4(p)) {
182
5.57k
        f->icmp_s.type = p->icmp_s.type;
183
5.57k
        f->icmp_s.code = p->icmp_s.code;
184
5.57k
        FlowSetICMPv4CounterPart(f);
185
21.1k
    } else if (PacketIsICMPv6(p)) {
186
17.9k
        f->icmp_s.type = p->icmp_s.type;
187
17.9k
        f->icmp_s.code = p->icmp_s.code;
188
17.9k
        FlowSetICMPv6CounterPart(f);
189
17.9k
    } else if (PacketIsSCTP(p)) {
190
856
        f->sp = p->sp;
191
856
        f->dp = p->dp;
192
2.36k
    } else if (PacketIsESP(p)) {
193
926
        f->esp.spi = ESP_GET_SPI(PacketGetESP(p));
194
1.44k
    } else {
195
        /* nothing to do for this IP proto. */
196
1.44k
        SCLogDebug("no special setup for IP proto %u", p->proto);
197
1.44k
    }
198
485k
    f->startts = p->ts;
199
200
485k
    f->protomap = FlowGetProtoMapping(f->proto);
201
485k
    f->timeout_policy = FlowGetTimeoutPolicy(f);
202
203
485k
    if (MacSetFlowStorageEnabled()) {
204
0
        DEBUG_VALIDATE_BUG_ON(FlowGetStorageById(f, MacSetGetFlowStorageID()) != NULL);
205
0
        MacSet *ms = MacSetInit(10);
206
0
        FlowSetStorageById(f, MacSetGetFlowStorageID(), ms);
207
0
    }
208
209
485k
    if (FlowRateStorageEnabled()) {
210
0
        DEBUG_VALIDATE_BUG_ON(FlowGetStorageById(f, FlowRateGetStorageID()) != NULL);
211
0
        FlowRateStore *frs = FlowRateStoreInit();
212
0
        FlowSetStorageById(f, FlowRateGetStorageID(), frs);
213
0
    }
214
215
485k
    SCFlowRunInitCallbacks(tv, f, p);
216
217
485k
    SCReturn;
218
485k
}
219
220
FlowStorageId g_bypass_info_id = { .id = -1 };
221
222
FlowStorageId GetFlowBypassInfoID(void)
223
926k
{
224
926k
    return g_bypass_info_id;
225
926k
}
226
227
static void FlowBypassFree(void *x)
228
0
{
229
0
    FlowBypassInfo *fb = (FlowBypassInfo *) x;
230
231
0
    if (fb == NULL)
232
0
        return;
233
234
0
    if (fb->bypass_data && fb->BypassFree) {
235
0
        fb->BypassFree(fb->bypass_data);
236
0
    }
237
0
    SCFree(fb);
238
0
}
239
240
void RegisterFlowBypassInfo(void)
241
11
{
242
11
    g_bypass_info_id = FlowStorageRegister("bypass_counters", sizeof(void *),
243
11
                                              NULL, FlowBypassFree);
244
11
}
245
246
void FlowEndCountersRegister(ThreadVars *t, FlowEndCounters *fec)
247
5
{
248
25
    for (int i = 0; i < FLOW_STATE_SIZE; i++) {
249
20
        const char *name = NULL;
250
20
        if (i == FLOW_STATE_NEW) {
251
5
            name = "flow.end.state.new";
252
15
        } else if (i == FLOW_STATE_ESTABLISHED) {
253
5
            name = "flow.end.state.established";
254
10
        } else if (i == FLOW_STATE_CLOSED) {
255
5
            name = "flow.end.state.closed";
256
5
        } else if (i == FLOW_STATE_LOCAL_BYPASSED) {
257
5
            name = "flow.end.state.local_bypassed";
258
#ifdef CAPTURE_OFFLOAD
259
        } else if (i == FLOW_STATE_CAPTURE_BYPASSED) {
260
            name = "flow.end.state.capture_bypassed";
261
#endif
262
5
        }
263
20
        if (name) {
264
20
            fec->flow_state[i] = StatsRegisterCounter(name, t);
265
20
        }
266
20
    }
267
268
65
    for (enum TcpState i = TCP_NONE; i <= TCP_CLOSED; i++) {
269
60
        const char *name = NULL;
270
60
        switch (i) {
271
5
            case TCP_NONE:
272
5
                name = "flow.end.tcp_state.none";
273
5
                break;
274
5
            case TCP_SYN_SENT:
275
5
                name = "flow.end.tcp_state.syn_sent";
276
5
                break;
277
5
            case TCP_SYN_RECV:
278
5
                name = "flow.end.tcp_state.syn_recv";
279
5
                break;
280
5
            case TCP_ESTABLISHED:
281
5
                name = "flow.end.tcp_state.established";
282
5
                break;
283
5
            case TCP_FIN_WAIT1:
284
5
                name = "flow.end.tcp_state.fin_wait1";
285
5
                break;
286
5
            case TCP_FIN_WAIT2:
287
5
                name = "flow.end.tcp_state.fin_wait2";
288
5
                break;
289
5
            case TCP_TIME_WAIT:
290
5
                name = "flow.end.tcp_state.time_wait";
291
5
                break;
292
5
            case TCP_LAST_ACK:
293
5
                name = "flow.end.tcp_state.last_ack";
294
5
                break;
295
5
            case TCP_CLOSE_WAIT:
296
5
                name = "flow.end.tcp_state.close_wait";
297
5
                break;
298
5
            case TCP_CLOSING:
299
5
                name = "flow.end.tcp_state.closing";
300
5
                break;
301
5
            case TCP_CLOSED:
302
5
                name = "flow.end.tcp_state.closed";
303
5
                break;
304
60
        }
305
306
60
        fec->flow_tcp_state[i] = StatsRegisterCounter(name, t);
307
60
    }
308
5
    fec->flow_tcp_liberal = StatsRegisterCounter("flow.end.tcp_liberal", t);
309
5
}