suricata
flow-timeout.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2024 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 Anoop Saldanha <anoopsaldanha@gmail.com>
22 */
23
24#include "suricata-common.h"
25#include "suricata.h"
26#include "decode.h"
27#include "conf.h"
28#include "threadvars.h"
29#include "tm-threads.h"
30#include "runmodes.h"
31
32#include "util-random.h"
33#include "util-time.h"
34
35#include "flow.h"
36#include "flow-queue.h"
37#include "flow-hash.h"
38#include "flow-util.h"
39#include "flow-var.h"
40#include "flow-private.h"
41#include "flow-manager.h"
42#include "flow-timeout.h"
43#include "pkt-var.h"
44#include "host.h"
45
46#include "stream-tcp-private.h"
48#include "stream-tcp.h"
49
50#include "util-unittest.h"
52#include "util-byte.h"
53
54#include "util-debug.h"
55#include "util-privs.h"
56#include "util-datalink.h"
57
58#include "detect.h"
59#include "detect-engine-state.h"
60#include "stream.h"
61
62#include "app-layer-frames.h"
63#include "app-layer-parser.h"
64#include "app-layer.h"
65
66#include "util-profiling.h"
67
68/**
69 * \internal
70 * \brief Pseudo packet setup to finish a flow when needed.
71 *
72 * \param p a dummy pseudo packet from packet pool. Not all pseudo
73 * packets need to force reassembly, in which case we just
74 * set dummy ack/seq values.
75 * \param direction Direction of the packet. 0 indicates toserver and 1
76 * indicates toclient.
77 * \param f Pointer to the flow.
78 * \param ssn Pointer to the tcp session.
79 * \retval pseudo packet with everything set up
80 */
81static inline Packet *FlowPseudoPacketSetup(
82 Packet *p, int direction, Flow *f, const TcpSession *ssn)
83{
84 const int orig_dir = direction;
85 p->tenant_id = f->tenant_id;
87 p->proto = IPPROTO_TCP;
88 FlowReference(&p->flow, f);
90 p->flags |= PKT_HAS_FLOW;
92 memcpy(&p->vlan_id[0], &f->vlan_id[0], sizeof(p->vlan_id));
93 p->vlan_idx = f->vlan_idx;
94 p->livedev = (struct LiveDevice_ *)f->livedev;
95
96 if (f->flags & FLOW_NOPAYLOAD_INSPECTION) {
97 DecodeSetNoPayloadInspectionFlag(p);
98 }
99
100 if (direction == 0)
101 p->flowflags |= FLOW_PKT_TOSERVER;
102 else
103 p->flowflags |= FLOW_PKT_TOCLIENT;
104 p->flowflags |= FLOW_PKT_ESTABLISHED;
105 p->payload = NULL;
106 p->payload_len = 0;
107
108 /* apply reversed flow logic after setting direction to the packet */
109 direction ^= ((f->flags & FLOW_DIR_REVERSED) != 0);
110
111 if (FLOW_IS_IPV4(f)) {
112 if (direction == 0) {
113 FLOW_COPY_IPV4_ADDR_TO_PACKET(&f->src, &p->src);
114 FLOW_COPY_IPV4_ADDR_TO_PACKET(&f->dst, &p->dst);
115 p->sp = f->sp;
116 p->dp = f->dp;
117 } else {
118 FLOW_COPY_IPV4_ADDR_TO_PACKET(&f->src, &p->dst);
119 FLOW_COPY_IPV4_ADDR_TO_PACKET(&f->dst, &p->src);
120 p->sp = f->dp;
121 p->dp = f->sp;
122 }
123
124 /* Check if we have enough room in direct data. We need ipv4 hdr + tcp hdr.
125 * Force an allocation if it is not the case.
126 */
127 if (GET_PKT_DIRECT_MAX_SIZE(p) < 40) {
128 if (PacketCallocExtPkt(p, 40) == -1) {
129 goto error;
130 }
131 }
132 /* set the ip header */
133 IPV4Hdr *ip4h = PacketSetIPV4(p, GET_PKT_DATA(p));
134 /* version 4 and length 20 bytes for the tcp header */
135 ip4h->ip_verhl = 0x45;
136 ip4h->ip_tos = 0;
137 ip4h->ip_len = htons(40);
138 ip4h->ip_id = 0;
139 ip4h->ip_off = 0;
140 ip4h->ip_ttl = 64;
141 ip4h->ip_proto = IPPROTO_TCP;
142 //p->ip4h->ip_csum =
143 if (direction == 0) {
144 ip4h->s_ip_src.s_addr = f->src.addr_data32[0];
145 ip4h->s_ip_dst.s_addr = f->dst.addr_data32[0];
146 } else {
147 ip4h->s_ip_src.s_addr = f->dst.addr_data32[0];
148 ip4h->s_ip_dst.s_addr = f->src.addr_data32[0];
149 }
150
151 /* set the tcp header */
152 PacketSetTCP(p, GET_PKT_DATA(p) + 20);
153
154 SET_PKT_LEN(p, 40); /* ipv4 hdr + tcp hdr */
155
156 } else if (FLOW_IS_IPV6(f)) {
157 if (direction == 0) {
158 FLOW_COPY_IPV6_ADDR_TO_PACKET(&f->src, &p->src);
159 FLOW_COPY_IPV6_ADDR_TO_PACKET(&f->dst, &p->dst);
160 p->sp = f->sp;
161 p->dp = f->dp;
162 } else {
163 FLOW_COPY_IPV6_ADDR_TO_PACKET(&f->src, &p->dst);
164 FLOW_COPY_IPV6_ADDR_TO_PACKET(&f->dst, &p->src);
165 p->sp = f->dp;
166 p->dp = f->sp;
167 }
168
169 /* Check if we have enough room in direct data. We need ipv6 hdr + tcp hdr.
170 * Force an allocation if it is not the case.
171 */
172 if (GET_PKT_DIRECT_MAX_SIZE(p) < 60) {
173 if (PacketCallocExtPkt(p, 60) == -1) {
174 goto error;
175 }
176 }
177 /* set the ip header */
178 IPV6Hdr *ip6h = PacketSetIPV6(p, GET_PKT_DATA(p));
179 /* version 6 */
180 ip6h->s_ip6_vfc = 0x60;
181 ip6h->s_ip6_flow = 0;
182 ip6h->s_ip6_nxt = IPPROTO_TCP;
183 ip6h->s_ip6_plen = htons(20);
184 ip6h->s_ip6_hlim = 64;
185 if (direction == 0) {
186 ip6h->s_ip6_src[0] = f->src.addr_data32[0];
187 ip6h->s_ip6_src[1] = f->src.addr_data32[1];
188 ip6h->s_ip6_src[2] = f->src.addr_data32[2];
189 ip6h->s_ip6_src[3] = f->src.addr_data32[3];
190 ip6h->s_ip6_dst[0] = f->dst.addr_data32[0];
191 ip6h->s_ip6_dst[1] = f->dst.addr_data32[1];
192 ip6h->s_ip6_dst[2] = f->dst.addr_data32[2];
193 ip6h->s_ip6_dst[3] = f->dst.addr_data32[3];
194 } else {
195 ip6h->s_ip6_src[0] = f->dst.addr_data32[0];
196 ip6h->s_ip6_src[1] = f->dst.addr_data32[1];
197 ip6h->s_ip6_src[2] = f->dst.addr_data32[2];
198 ip6h->s_ip6_src[3] = f->dst.addr_data32[3];
199 ip6h->s_ip6_dst[0] = f->src.addr_data32[0];
200 ip6h->s_ip6_dst[1] = f->src.addr_data32[1];
201 ip6h->s_ip6_dst[2] = f->src.addr_data32[2];
202 ip6h->s_ip6_dst[3] = f->src.addr_data32[3];
203 }
204
205 /* set the tcp header */
206 PacketSetTCP(p, GET_PKT_DATA(p) + 40);
207
208 SET_PKT_LEN(p, 60); /* ipv6 hdr + tcp hdr */
209 }
210
211 p->l4.hdrs.tcph->th_offx2 = 0x50;
212 p->l4.hdrs.tcph->th_flags = 0;
213 p->l4.hdrs.tcph->th_win = 10;
214 p->l4.hdrs.tcph->th_urp = 0;
215
216 /* to server */
217 if (orig_dir == 0) {
218 p->l4.hdrs.tcph->th_sport = htons(f->sp);
219 p->l4.hdrs.tcph->th_dport = htons(f->dp);
220
221 p->l4.hdrs.tcph->th_seq = htonl(ssn->client.next_seq);
222 p->l4.hdrs.tcph->th_ack = 0;
223
224 /* to client */
225 } else {
226 p->l4.hdrs.tcph->th_sport = htons(f->dp);
227 p->l4.hdrs.tcph->th_dport = htons(f->sp);
228
229 p->l4.hdrs.tcph->th_seq = htonl(ssn->server.next_seq);
230 p->l4.hdrs.tcph->th_ack = 0;
231 }
232
233 if (FLOW_IS_IPV4(f)) {
234 IPV4Hdr *ip4h = p->l3.hdrs.ip4h;
235 p->l4.hdrs.tcph->th_sum = TCPChecksum(ip4h->s_ip_addrs, (uint16_t *)p->l4.hdrs.tcph, 20, 0);
236 /* calc ipv4 csum as we may log it and barnyard might reject
237 * a wrong checksum */
238 ip4h->ip_csum = IPV4Checksum((uint16_t *)ip4h, IPV4_GET_RAW_HLEN(ip4h), 0);
239 } else if (FLOW_IS_IPV6(f)) {
240 const IPV6Hdr *ip6h = PacketGetIPv6(p);
241 p->l4.hdrs.tcph->th_sum =
242 TCPChecksum(ip6h->s_ip6_addrs, (uint16_t *)p->l4.hdrs.tcph, 20, 0);
243 }
244
245 p->ts = TimeGet();
246
247 if (direction == 0) {
248 if (f->alparser && !STREAM_HAS_SEEN_DATA(&ssn->client)) {
250 }
251 } else {
252 if (f->alparser && !STREAM_HAS_SEEN_DATA(&ssn->server)) {
254 }
255 }
256
257 return p;
258
259error:
260 FlowDeReference(&p->flow);
261 return NULL;
262}
263
264Packet *FlowPseudoPacketGet(int direction, Flow *f, const TcpSession *ssn)
265{
268 if (p == NULL) {
269 return NULL;
270 }
271
273
274 return FlowPseudoPacketSetup(p, direction, f, ssn);
275}
276
277/**
278 * \brief Check if a flow needs forced reassembly, or any other processing
279 *
280 * \param f *LOCKED* flow
281 *
282 * \retval false no
283 * \retval true yes
284 */
286{
287 if (f == NULL || f->protoctx == NULL) {
288 return false;
289 }
290
291 TcpSession *ssn = (TcpSession *)f->protoctx;
292 uint8_t client = StreamNeedsReassembly(ssn, STREAM_TOSERVER);
293 uint8_t server = StreamNeedsReassembly(ssn, STREAM_TOCLIENT);
294
295 /* if state is not fully closed we assume that we haven't fully
296 * inspected the app layer state yet */
297 if (ssn->state >= TCP_ESTABLISHED && ssn->state != TCP_CLOSED)
298 {
301 }
302
303 /* if app layer still needs some love, push through */
304 if (f->alproto != ALPROTO_UNKNOWN && f->alstate != NULL) {
305 const uint64_t total_txs = AppLayerParserGetTxCnt(f, f->alstate);
306
307 if (AppLayerParserGetTransactionActive(f, f->alparser, STREAM_TOCLIENT) < total_txs)
308 {
310 }
311 if (AppLayerParserGetTransactionActive(f, f->alparser, STREAM_TOSERVER) < total_txs)
312 {
314 }
315 }
316
317 /* if any frame is present we assume it still needs work */
318 FramesContainer *frames_container = AppLayerFramesGetContainer(f);
319 if (frames_container) {
320 if (frames_container->toserver.cnt)
322 if (frames_container->toclient.cnt)
324 }
325
326 /* nothing to do */
329 return false;
330 }
331
332 f->ffr_ts = client;
333 f->ffr_tc = server;
334 return true;
335}
336
337/**
338 * \internal
339 * \brief Sends the flow to its respective thread's flow queue.
340 *
341 * The function requires flow to be locked beforehand.
342 *
343 * Normally, the first thread_id value should be used. This is when the flow is
344 * created on seeing the first packet to the server; when the flow's reversed
345 * flag is set, choose the second thread_id (to client/source).
346 *
347 * \param f Pointer to the flow.
348 */
350{
351 // Choose the thread_id based on whether the flow has been
352 // reversed.
353 int idx = f->flags & FLOW_DIR_REVERSED ? 1 : 0;
354 TmThreadsInjectFlowById(f, (const int)f->thread_id[idx]);
355}
356
357/**
358 * \internal
359 * \brief Remove flows from the hash bucket as they have more work to be done in
360 * in the detection engine.
361 *
362 * When this function is called we're running in virtually dead engine,
363 * so locking the flows is not strictly required. The reasons it is still
364 * done are:
365 * - code consistency
366 * - silence complaining profilers
367 * - allow us to aggressively check using debug validation assertions
368 * - be robust in case of future changes
369 * - locking overhead is negligible when no other thread fights us
370 */
371static inline void FlowRemoveHash(void)
372{
373 for (uint32_t idx = 0; idx < flow_config.hash_size; idx++) {
374 FlowBucket *fb = &flow_hash[idx];
375 FBLOCK_LOCK(fb);
376
377 Flow *f = fb->head;
378 Flow *prev_f = NULL;
379
380 /* we need to loop through all the flows in the queue */
381 while (f != NULL) {
382 Flow *next_f = f->next;
383
385
386 /* Get the tcp session for the flow */
387 TcpSession *ssn = (TcpSession *)f->protoctx;
388 /* \todo Also skip flows that shouldn't be inspected */
389 if (ssn == NULL) {
391 prev_f = f;
392 f = next_f;
393 continue;
394 }
395
396 /* in case of additional work, we pull the flow out of the
397 * hash and xfer ownership to the injected packet(s) */
398 if (FlowNeedsReassembly(f)) {
399 RemoveFromHash(f, prev_f);
403 f = next_f;
404 continue;
405 }
406
408
409 /* next flow in the queue */
410 prev_f = f;
411 f = f->next;
412 }
413 FBLOCK_UNLOCK(fb);
414 }
415}
416
417/**
418 * \brief Clean up all the flows that have unprocessed segments and have
419 * some work to do in the detection engine.
420 */
422{
423 /* Carry out cleanup of unattended flows */
424 FlowRemoveHash();
425}
FramesContainer * AppLayerFramesGetContainer(Flow *f)
uint64_t AppLayerParserGetTransactionActive(const Flow *f, AppLayerParserState *pstate, uint8_t direction)
uint64_t AppLayerParserGetTxCnt(const Flow *f, void *alstate)
void SCAppLayerParserStateSetFlag(AppLayerParserState *pstate, uint16_t flag)
#define APP_LAYER_PARSER_EOF_TC
#define APP_LAYER_PARSER_EOF_TS
@ ALPROTO_UNKNOWN
#define IPV4_GET_RAW_HLEN(ip4h)
Definition decode-ipv4.h:96
#define PKT_HAS_FLOW
Definition decode.h:1266
#define GET_PKT_DIRECT_MAX_SIZE(p)
Definition decode.h:211
#define SET_PKT_LEN(p, len)
Definition decode.h:213
#define PKT_PSEUDO_STREAM_END
Definition decode.h:1268
#define GET_PKT_DATA(p)
Definition decode.h:209
#define PKT_STREAM_EST
Definition decode.h:1262
Data structures and function prototypes for keeping state for the detection engine.
FlowBucket * flow_hash
Definition flow-hash.c:59
#define FBLOCK_LOCK(fb)
Definition flow-hash.h:73
#define FBLOCK_UNLOCK(fb)
Definition flow-hash.h:75
FlowConfig flow_config
Definition flow.c:93
Packet * FlowPseudoPacketGet(int direction, Flow *f, const TcpSession *ssn)
void FlowWorkToDoCleanup(void)
Clean up all the flows that have unprocessed segments and have some work to do in the detection engin...
void FlowSendToLocalThread(Flow *f)
bool FlowNeedsReassembly(Flow *f)
Check if a flow needs forced reassembly, or any other processing.
#define FLOW_NOPAYLOAD_INSPECTION
Definition flow.h:67
#define FLOW_IS_IPV6(f)
Definition flow.h:172
#define FLOW_PKT_TOSERVER
Definition flow.h:233
#define FLOW_DIR_REVERSED
Definition flow.h:112
#define FLOW_COPY_IPV4_ADDR_TO_PACKET(fa, pa)
Definition flow.h:180
#define FLOW_COPY_IPV6_ADDR_TO_PACKET(fa, pa)
Definition flow.h:185
#define FLOW_END_FLAG_SHUTDOWN
Definition flow.h:245
#define FLOW_PKT_ESTABLISHED
Definition flow.h:235
#define FLOWLOCK_UNLOCK(fb)
Definition flow.h:273
#define FLOW_IS_IPV4(f)
Definition flow.h:170
#define FLOW_PKT_TOCLIENT
Definition flow.h:234
#define FLOWLOCK_WRLOCK(fb)
Definition flow.h:270
int PacketCallocExtPkt(Packet *p, int datalen)
Definition decode.c:309
@ TCP_ESTABLISHED
@ TCP_CLOSED
#define STREAM_HAS_SEEN_DATA(stream)
uint8_t StreamNeedsReassembly(const TcpSession *ssn, uint8_t direction)
see what if any work the TCP session still needs
@ STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION
Definition stream-tcp.h:193
@ STREAM_HAS_UNPROCESSED_SEGMENTS_NONE
Definition stream-tcp.h:190
uint32_t hash_size
Definition flow.h:294
Flow data structure.
Definition flow.h:356
uint8_t ffr_tc
Definition flow.h:388
uint32_t flags
Definition flow.h:421
uint8_t ffr_ts
Definition flow.h:387
uint8_t flow_end_flags
Definition flow.h:447
AppProto alproto
application level protocol
Definition flow.h:450
void * alstate
Definition flow.h:479
uint32_t tenant_id
Definition flow.h:416
uint8_t vlan_idx
Definition flow.h:382
void * protoctx
Definition flow.h:441
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition flow.h:380
AppLayerParserState * alparser
Definition flow.h:478
struct LiveDevice_ * livedev
Definition flow.h:398
FlowThreadId thread_id[2]
Definition flow.h:394
struct Flow_ * next
Definition flow.h:396
uint16_t cnt
uint8_t ip_verhl
Definition decode-ipv4.h:73
uint16_t ip_id
Definition decode-ipv4.h:76
uint8_t ip_tos
Definition decode-ipv4.h:74
uint16_t ip_off
Definition decode-ipv4.h:77
uint16_t ip_csum
Definition decode-ipv4.h:80
uint8_t ip_proto
Definition decode-ipv4.h:79
uint8_t ip_ttl
Definition decode-ipv4.h:78
uint16_t ip_len
Definition decode-ipv4.h:75
uint32_t tenant_id
Definition decode.h:665
struct Flow_ * flow
Definition decode.h:546
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition decode.h:528
int datalink
Definition decode.h:639
struct LiveDevice_ * livedev
Definition decode.h:618
uint32_t flags
Definition decode.h:544
uint8_t vlan_idx
Definition decode.h:529
uint8_t proto
Definition decode.h:523
void TmThreadsInjectFlowById(Flow *f, const int id)
inject a flow into a threads flow queue
void PacketPoolWait(void)
Packet * PacketPoolGetPacket(void)
Get a new packet from the packet pool.
#define PACKET_PROFILING_START(p)
SCTime_t TimeGet(void)
Definition util-time.c:152