Coverage Report

Created: 2026-06-30 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/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-var.h"
33
#include "app-layer.h"
34
35
#include "util-var.h"
36
#include "util-debug.h"
37
#include "util-macset.h"
38
#include "flow-storage.h"
39
40
#include "detect.h"
41
#include "detect-engine-state.h"
42
43
#include "decode-icmpv4.h"
44
45
#include "util-validate.h"
46
47
/** \brief allocate a flow
48
 *
49
 *  We check against the memuse counter. If it passes that check we increment
50
 *  the counter first, then we try to alloc.
51
 *
52
 *  \retval f the flow or NULL on out of memory
53
 */
54
Flow *FlowAlloc(void)
55
1.45M
{
56
1.45M
    Flow *f;
57
1.45M
    size_t size = sizeof(Flow) + FlowStorageSize();
58
59
1.45M
    if (!(FLOW_CHECK_MEMCAP(size))) {
60
0
        return NULL;
61
0
    }
62
63
1.45M
    (void) SC_ATOMIC_ADD(flow_memuse, size);
64
65
1.45M
    f = SCMalloc(size);
66
1.45M
    if (unlikely(f == NULL)) {
67
0
        (void)SC_ATOMIC_SUB(flow_memuse, size);
68
0
        return NULL;
69
0
    }
70
1.45M
    memset(f, 0, size);
71
72
    /* coverity[missing_lock] */
73
1.45M
    FLOW_INITIALIZE(f);
74
1.45M
    return f;
75
1.45M
}
76
77
78
/**
79
 *  \brief cleanup & free the memory of a flow
80
 *
81
 *  \param f flow to clear & destroy
82
 */
83
void FlowFree(Flow *f)
84
780k
{
85
780k
    FLOW_DESTROY(f);
86
780k
    SCFree(f);
87
88
780k
    size_t size = sizeof(Flow) + FlowStorageSize();
89
780k
    (void) SC_ATOMIC_SUB(flow_memuse, size);
90
780k
}
91
92
/**
93
 *  \brief   Function to map the protocol to the defined FLOW_PROTO_* enumeration.
94
 *
95
 *  \param   proto  protocol which is needed to be mapped
96
 */
97
98
uint8_t FlowGetProtoMapping(uint8_t proto)
99
6.02G
{
100
6.02G
    switch (proto) {
101
3.67G
        case IPPROTO_TCP:
102
3.67G
            return FLOW_PROTO_TCP;
103
2.34G
        case IPPROTO_UDP:
104
2.34G
            return FLOW_PROTO_UDP;
105
37.2k
        case IPPROTO_ICMP:
106
37.2k
            return FLOW_PROTO_ICMP;
107
189k
        default:
108
189k
            return FLOW_PROTO_DEFAULT;
109
6.02G
    }
110
6.02G
}
111
112
uint8_t FlowGetReverseProtoMapping(uint8_t rproto)
113
5.91M
{
114
5.91M
    switch (rproto) {
115
1.97M
        case FLOW_PROTO_TCP:
116
1.97M
            return IPPROTO_TCP;
117
1.97M
        case FLOW_PROTO_UDP:
118
1.97M
            return IPPROTO_UDP;
119
1.97M
        case FLOW_PROTO_ICMP:
120
1.97M
            return IPPROTO_ICMP;
121
0
        default:
122
0
            exit(EXIT_FAILURE);
123
5.91M
    }
124
5.91M
}
125
126
static inline void FlowSetICMPv4CounterPart(Flow *f)
127
4.65k
{
128
4.65k
    int ctype = ICMPv4GetCounterpart(f->icmp_s.type);
129
4.65k
    if (ctype == -1)
130
2.03k
        return;
131
132
2.62k
    f->icmp_d.type = (uint8_t)ctype;
133
2.62k
}
134
135
static inline void FlowSetICMPv6CounterPart(Flow *f)
136
18.0k
{
137
18.0k
    int ctype = ICMPv6GetCounterpart(f->icmp_s.type);
138
18.0k
    if (ctype == -1)
139
10.4k
        return;
140
141
7.63k
    f->icmp_d.type = (uint8_t)ctype;
142
7.63k
}
143
144
/* initialize the flow from the first packet
145
 * we see from it. */
146
void FlowInit(ThreadVars *tv, Flow *f, const Packet *p)
147
238k
{
148
238k
    SCEnter();
149
238k
    SCLogDebug("flow %p", f);
150
151
238k
    f->proto = p->proto;
152
238k
    f->recursion_level = p->recursion_level;
153
238k
    memcpy(&f->vlan_id[0], &p->vlan_id[0], sizeof(f->vlan_id));
154
238k
    f->vlan_idx = p->vlan_idx;
155
156
238k
    f->thread_id[0] = (FlowThreadId)tv->id;
157
158
238k
    f->livedev = p->livedev;
159
160
238k
    if (PKT_IS_IPV4(p)) {
161
205k
        FLOW_SET_IPV4_SRC_ADDR_FROM_PACKET(p, &f->src);
162
205k
        FLOW_SET_IPV4_DST_ADDR_FROM_PACKET(p, &f->dst);
163
205k
        f->min_ttl_toserver = f->max_ttl_toserver = IPV4_GET_IPTTL((p));
164
205k
        f->flags |= FLOW_IPV4;
165
205k
    } else if (PKT_IS_IPV6(p)) {
166
33.0k
        FLOW_SET_IPV6_SRC_ADDR_FROM_PACKET(p, &f->src);
167
33.0k
        FLOW_SET_IPV6_DST_ADDR_FROM_PACKET(p, &f->dst);
168
33.0k
        f->min_ttl_toserver = f->max_ttl_toserver = IPV6_GET_HLIM((p));
169
33.0k
        f->flags |= FLOW_IPV6;
170
33.0k
    } else {
171
0
        SCLogDebug("neither IPv4 or IPv6, weird");
172
0
        DEBUG_VALIDATE_BUG_ON(1);
173
0
    }
174
175
238k
    if (p->tcph != NULL) { /* XXX MACRO */
176
197k
        SET_TCP_SRC_PORT(p,&f->sp);
177
197k
        SET_TCP_DST_PORT(p,&f->dp);
178
197k
    } else if (p->udph != NULL) { /* XXX MACRO */
179
27.8k
        SET_UDP_SRC_PORT(p,&f->sp);
180
27.8k
        SET_UDP_DST_PORT(p,&f->dp);
181
27.8k
    } else if (p->icmpv4h != NULL) {
182
1.85k
        f->icmp_s.type = p->icmp_s.type;
183
1.85k
        f->icmp_s.code = p->icmp_s.code;
184
1.85k
        FlowSetICMPv4CounterPart(f);
185
11.1k
    } else if (p->icmpv6h != NULL) {
186
7.75k
        f->icmp_s.type = p->icmp_s.type;
187
7.75k
        f->icmp_s.code = p->icmp_s.code;
188
7.75k
        FlowSetICMPv6CounterPart(f);
189
7.75k
    } else if (p->sctph != NULL) { /* XXX MACRO */
190
352
        SET_SCTP_SRC_PORT(p,&f->sp);
191
352
        SET_SCTP_DST_PORT(p,&f->dp);
192
3.07k
    } else if (p->esph != NULL) {
193
2.99k
        f->esp.spi = ESP_GET_SPI(p);
194
2.99k
    } else {
195
        /* nothing to do for this IP proto. */
196
84
        SCLogDebug("no special setup for IP proto %u", p->proto);
197
84
    }
198
238k
    f->startts = p->ts;
199
200
238k
    f->protomap = FlowGetProtoMapping(f->proto);
201
238k
    f->timeout_policy = FlowGetTimeoutPolicy(f);
202
238k
    const uint32_t timeout_at = (uint32_t)SCTIME_SECS(f->startts) + f->timeout_policy;
203
238k
    f->timeout_at = timeout_at;
204
205
238k
    if (MacSetFlowStorageEnabled()) {
206
0
        DEBUG_VALIDATE_BUG_ON(FlowGetStorageById(f, MacSetGetFlowStorageID()) != NULL);
207
0
        MacSet *ms = MacSetInit(10);
208
0
        FlowSetStorageById(f, MacSetGetFlowStorageID(), ms);
209
0
    }
210
211
238k
    SCReturn;
212
238k
}
213
214
FlowStorageId g_bypass_info_id = { .id = -1 };
215
216
FlowStorageId GetFlowBypassInfoID(void)
217
1.01M
{
218
1.01M
    return g_bypass_info_id;
219
1.01M
}
220
221
static void FlowBypassFree(void *x)
222
0
{
223
0
    FlowBypassInfo *fb = (FlowBypassInfo *) x;
224
225
0
    if (fb == NULL)
226
0
        return;
227
228
0
    if (fb->bypass_data && fb->BypassFree) {
229
0
        fb->BypassFree(fb->bypass_data);
230
0
    }
231
0
    SCFree(fb);
232
0
}
233
234
void RegisterFlowBypassInfo(void)
235
74
{
236
74
    g_bypass_info_id = FlowStorageRegister("bypass_counters", sizeof(void *),
237
74
                                              NULL, FlowBypassFree);
238
74
}
239
240
void FlowEndCountersRegister(ThreadVars *t, FlowEndCounters *fec)
241
4
{
242
20
    for (int i = 0; i < FLOW_STATE_SIZE; i++) {
243
16
        const char *name = NULL;
244
16
        if (i == FLOW_STATE_NEW) {
245
4
            name = "flow.end.state.new";
246
12
        } else if (i == FLOW_STATE_ESTABLISHED) {
247
4
            name = "flow.end.state.established";
248
8
        } else if (i == FLOW_STATE_CLOSED) {
249
4
            name = "flow.end.state.closed";
250
4
        } else if (i == FLOW_STATE_LOCAL_BYPASSED) {
251
4
            name = "flow.end.state.local_bypassed";
252
#ifdef CAPTURE_OFFLOAD
253
        } else if (i == FLOW_STATE_CAPTURE_BYPASSED) {
254
            name = "flow.end.state.capture_bypassed";
255
#endif
256
4
        }
257
16
        if (name) {
258
16
            fec->flow_state[i] = StatsRegisterCounter(name, t);
259
16
        }
260
16
    }
261
262
52
    for (enum TcpState i = TCP_NONE; i <= TCP_CLOSED; i++) {
263
48
        const char *name = NULL;
264
48
        switch (i) {
265
4
            case TCP_NONE:
266
4
                name = "flow.end.tcp_state.none";
267
4
                break;
268
4
            case TCP_SYN_SENT:
269
4
                name = "flow.end.tcp_state.syn_sent";
270
4
                break;
271
4
            case TCP_SYN_RECV:
272
4
                name = "flow.end.tcp_state.syn_recv";
273
4
                break;
274
4
            case TCP_ESTABLISHED:
275
4
                name = "flow.end.tcp_state.established";
276
4
                break;
277
4
            case TCP_FIN_WAIT1:
278
4
                name = "flow.end.tcp_state.fin_wait1";
279
4
                break;
280
4
            case TCP_FIN_WAIT2:
281
4
                name = "flow.end.tcp_state.fin_wait2";
282
4
                break;
283
4
            case TCP_TIME_WAIT:
284
4
                name = "flow.end.tcp_state.time_wait";
285
4
                break;
286
4
            case TCP_LAST_ACK:
287
4
                name = "flow.end.tcp_state.last_ack";
288
4
                break;
289
4
            case TCP_CLOSE_WAIT:
290
4
                name = "flow.end.tcp_state.close_wait";
291
4
                break;
292
4
            case TCP_CLOSING:
293
4
                name = "flow.end.tcp_state.closing";
294
4
                break;
295
4
            case TCP_CLOSED:
296
4
                name = "flow.end.tcp_state.closed";
297
4
                break;
298
48
        }
299
300
48
        fec->flow_tcp_state[i] = StatsRegisterCounter(name, t);
301
48
    }
302
4
    fec->flow_tcp_liberal = StatsRegisterCounter("flow.end.tcp_liberal", t);
303
4
}