You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
suricata/src/flow-timeout.c

501 lines
16 KiB
C

/* Copyright (C) 2007-2017 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Anoop Saldanha <anoopsaldanha@gmail.com>
*/
#include "suricata-common.h"
#include "suricata.h"
#include "decode.h"
#include "conf.h"
#include "threadvars.h"
#include "tm-threads.h"
#include "runmodes.h"
#include "util-random.h"
#include "util-time.h"
#include "flow.h"
#include "flow-queue.h"
#include "flow-hash.h"
#include "flow-util.h"
#include "flow-var.h"
#include "flow-private.h"
#include "flow-manager.h"
#include "flow-timeout.h"
#include "pkt-var.h"
#include "host.h"
#include "stream-tcp-private.h"
#include "stream-tcp-reassemble.h"
#include "stream-tcp.h"
#include "util-unittest.h"
#include "util-unittest-helper.h"
#include "util-byte.h"
#include "util-debug.h"
#include "util-privs.h"
#include "detect.h"
#include "detect-engine-state.h"
#include "stream.h"
#include "app-layer-parser.h"
App layer API rewritten. The main files in question are: app-layer.[ch], app-layer-detect-proto.[ch] and app-layer-parser.[ch]. Things addressed in this commit: - Brings out a proper separation between protocol detection phase and the parser phase. - The dns app layer now is registered such that we don't use "dnstcp" and "dnsudp" in the rules. A user who previously wrote a rule like this - "alert dnstcp....." or "alert dnsudp....." would now have to use, alert dns (ipproto:tcp;) or alert udp (app-layer-protocol:dns;) or alert ip (ipproto:udp; app-layer-protocol:dns;) The same rules extend to other another such protocol, dcerpc. - The app layer parser api now takes in the ipproto while registering callbacks. - The app inspection/detection engine also takes an ipproto. - All app layer parser functions now take direction as STREAM_TOSERVER or STREAM_TOCLIENT, as opposed to 0 or 1, which was taken by some of the functions. - FlowInitialize() and FlowRecycle() now resets proto to 0. This is needed by unittests, which would try to clean the flow, and that would call the api, AppLayerParserCleanupParserState(), which would try to clean the app state, but the app layer now needs an ipproto to figure out which api to internally call to clean the state, and if the ipproto is 0, it would return without trying to clean the state. - A lot of unittests are now updated where if they are using a flow and they need to use the app layer, we would set a flow ipproto. - The "app-layer" section in the yaml conf has also been updated as well.
12 years ago
#include "app-layer.h"
#include "util-profiling.h"
/**
* \internal
* \brief Pseudo packet setup for flow forced reassembly.
*
* \param direction Direction of the packet. 0 indicates toserver and 1
* indicates toclient.
* \param f Pointer to the flow.
* \param ssn Pointer to the tcp session.
* \param dummy Indicates to create a dummy pseudo packet. Not all pseudo
* packets need to force reassembly, in which case we just
* set dummy ack/seq values.
*/
static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p,
int direction,
Flow *f,
TcpSession *ssn,
int dummy)
{
p->tenant_id = f->tenant_id;
p->datalink = DLT_RAW;
p->proto = IPPROTO_TCP;
FlowReference(&p->flow, f);
p->flags |= PKT_STREAM_EST;
p->flags |= PKT_STREAM_EOF;
p->flags |= PKT_HAS_FLOW;
p->flags |= PKT_PSEUDO_STREAM_END;
if (f->flags & FLOW_NOPACKET_INSPECTION) {
DecodeSetNoPacketInspectionFlag(p);
}
if (f->flags & FLOW_NOPAYLOAD_INSPECTION) {
DecodeSetNoPayloadInspectionFlag(p);
}
if (direction == 0)
p->flowflags |= FLOW_PKT_TOSERVER;
else
p->flowflags |= FLOW_PKT_TOCLIENT;
p->flowflags |= FLOW_PKT_ESTABLISHED;
p->payload = NULL;
p->payload_len = 0;
if (FLOW_IS_IPV4(f)) {
if (direction == 0) {
FLOW_COPY_IPV4_ADDR_TO_PACKET(&f->src, &p->src);
FLOW_COPY_IPV4_ADDR_TO_PACKET(&f->dst, &p->dst);
p->sp = f->sp;
p->dp = f->dp;
} else {
FLOW_COPY_IPV4_ADDR_TO_PACKET(&f->src, &p->dst);
FLOW_COPY_IPV4_ADDR_TO_PACKET(&f->dst, &p->src);
p->sp = f->dp;
p->dp = f->sp;
}
/* Check if we have enough room in direct data. We need ipv4 hdr + tcp hdr.
* Force an allocation if it is not the case.
*/
if (GET_PKT_DIRECT_MAX_SIZE(p) < 40) {
if (PacketCallocExtPkt(p, 40) == -1) {
goto error;
}
}
/* set the ip header */
p->ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
/* version 4 and length 20 bytes for the tcp header */
p->ip4h->ip_verhl = 0x45;
p->ip4h->ip_tos = 0;
p->ip4h->ip_len = htons(40);
p->ip4h->ip_id = 0;
p->ip4h->ip_off = 0;
p->ip4h->ip_ttl = 64;
p->ip4h->ip_proto = IPPROTO_TCP;
//p->ip4h->ip_csum =
if (direction == 0) {
p->ip4h->s_ip_src.s_addr = f->src.addr_data32[0];
p->ip4h->s_ip_dst.s_addr = f->dst.addr_data32[0];
} else {
p->ip4h->s_ip_src.s_addr = f->dst.addr_data32[0];
p->ip4h->s_ip_dst.s_addr = f->src.addr_data32[0];
}
/* set the tcp header */
p->tcph = (TCPHdr *)((uint8_t *)GET_PKT_DATA(p) + 20);
SET_PKT_LEN(p, 40); /* ipv4 hdr + tcp hdr */
} else if (FLOW_IS_IPV6(f)) {
if (direction == 0) {
FLOW_COPY_IPV6_ADDR_TO_PACKET(&f->src, &p->src);
FLOW_COPY_IPV6_ADDR_TO_PACKET(&f->dst, &p->dst);
p->sp = f->sp;
p->dp = f->dp;
} else {
FLOW_COPY_IPV6_ADDR_TO_PACKET(&f->src, &p->dst);
FLOW_COPY_IPV6_ADDR_TO_PACKET(&f->dst, &p->src);
p->sp = f->dp;
p->dp = f->sp;
}
/* Check if we have enough room in direct data. We need ipv6 hdr + tcp hdr.
* Force an allocation if it is not the case.
*/
if (GET_PKT_DIRECT_MAX_SIZE(p) < 60) {
if (PacketCallocExtPkt(p, 60) == -1) {
goto error;
}
}
/* set the ip header */
p->ip6h = (IPV6Hdr *)GET_PKT_DATA(p);
/* version 6 */
p->ip6h->s_ip6_vfc = 0x60;
p->ip6h->s_ip6_flow = 0;
p->ip6h->s_ip6_nxt = IPPROTO_TCP;
p->ip6h->s_ip6_plen = htons(20);
p->ip6h->s_ip6_hlim = 64;
if (direction == 0) {
p->ip6h->s_ip6_src[0] = f->src.addr_data32[0];
p->ip6h->s_ip6_src[1] = f->src.addr_data32[1];
p->ip6h->s_ip6_src[2] = f->src.addr_data32[2];
p->ip6h->s_ip6_src[3] = f->src.addr_data32[3];
p->ip6h->s_ip6_dst[0] = f->dst.addr_data32[0];
p->ip6h->s_ip6_dst[1] = f->dst.addr_data32[1];
p->ip6h->s_ip6_dst[2] = f->dst.addr_data32[2];
p->ip6h->s_ip6_dst[3] = f->dst.addr_data32[3];
} else {
p->ip6h->s_ip6_src[0] = f->dst.addr_data32[0];
p->ip6h->s_ip6_src[1] = f->dst.addr_data32[1];
p->ip6h->s_ip6_src[2] = f->dst.addr_data32[2];
p->ip6h->s_ip6_src[3] = f->dst.addr_data32[3];
p->ip6h->s_ip6_dst[0] = f->src.addr_data32[0];
p->ip6h->s_ip6_dst[1] = f->src.addr_data32[1];
p->ip6h->s_ip6_dst[2] = f->src.addr_data32[2];
p->ip6h->s_ip6_dst[3] = f->src.addr_data32[3];
}
/* set the tcp header */
p->tcph = (TCPHdr *)((uint8_t *)GET_PKT_DATA(p) + 40);
SET_PKT_LEN(p, 60); /* ipv6 hdr + tcp hdr */
}
p->tcph->th_offx2 = 0x50;
p->tcph->th_flags |= TH_ACK;
p->tcph->th_win = 10;
p->tcph->th_urp = 0;
/* to server */
if (direction == 0) {
p->tcph->th_sport = htons(f->sp);
p->tcph->th_dport = htons(f->dp);
if (dummy) {
p->tcph->th_seq = htonl(ssn->client.next_seq);
p->tcph->th_ack = htonl(ssn->server.last_ack);
} else {
p->tcph->th_seq = htonl(ssn->client.next_seq);
p->tcph->th_ack = htonl(ssn->server.seg_list_tail->seq +
tcp: streaming implementation Make stream engine use the streaming buffer API for it's data storage. This means that the data is stored in a single reassembled sliding buffer. The subleties of the reassembly, e.g. overlap handling, are taken care of at segment insertion. The TcpSegments now have a StreamingBufferSegment that contains an offset and a length. Using this the segment data can be retrieved per segment. Redo segment insertion. The insertion code is moved to it's own file and is simplified a lot. A major difference with the previous implementation is that the segment list now contains overlapping segments if the traffic is that way. Previously there could be more and smaller segments in the memory list than what was seen on the wire. Due to the matching of in memory segments and on the wire segments, the overlap with different data detection (potential mots attacks) is much more accurate. Raw and App reassembly progress is no longer tracked per segment using flags, but there is now a progress tracker in the TcpStream for each. When pruning we make sure we don't slide beyond in-use segments. When both app-layer and raw inspection are beyond the start of the segment list, the segments might not be freed even though the data in the streaming buffer is already gone. This is caused by the 'in-use' status that the segments can implicitly have. This patch accounts for that when calculating the 'left_edge' of the streaming window. Raw reassembly still sets up 'StreamMsg' objects for content inspection. They are set up based on either the full StreamingBuffer, or based on the StreamingBufferBlocks if there are gaps in the data. Reworked 'stream needs work' logic. When a flow times out the flow engine checks whether a TCP flow still needs work. The StreamNeedsReassembly function is used to test if a stream still has unreassembled segments or uninspected stream chunks. This patch updates the function to consider the app and/or raw progress. It also cleans the function up and adds more meaningful debug messages. Finally it makes it non-inline. Unittests have been overhauled, and partly moved into their own files. Remove lots of dead code.
10 years ago
TCP_SEG_LEN(ssn->server.seg_list_tail));
}
/* to client */
} else {
p->tcph->th_sport = htons(f->dp);
p->tcph->th_dport = htons(f->sp);
if (dummy) {
p->tcph->th_seq = htonl(ssn->server.next_seq);
p->tcph->th_ack = htonl(ssn->client.last_ack);
} else {
p->tcph->th_seq = htonl(ssn->server.next_seq);
p->tcph->th_ack = htonl(ssn->client.seg_list_tail->seq +
tcp: streaming implementation Make stream engine use the streaming buffer API for it's data storage. This means that the data is stored in a single reassembled sliding buffer. The subleties of the reassembly, e.g. overlap handling, are taken care of at segment insertion. The TcpSegments now have a StreamingBufferSegment that contains an offset and a length. Using this the segment data can be retrieved per segment. Redo segment insertion. The insertion code is moved to it's own file and is simplified a lot. A major difference with the previous implementation is that the segment list now contains overlapping segments if the traffic is that way. Previously there could be more and smaller segments in the memory list than what was seen on the wire. Due to the matching of in memory segments and on the wire segments, the overlap with different data detection (potential mots attacks) is much more accurate. Raw and App reassembly progress is no longer tracked per segment using flags, but there is now a progress tracker in the TcpStream for each. When pruning we make sure we don't slide beyond in-use segments. When both app-layer and raw inspection are beyond the start of the segment list, the segments might not be freed even though the data in the streaming buffer is already gone. This is caused by the 'in-use' status that the segments can implicitly have. This patch accounts for that when calculating the 'left_edge' of the streaming window. Raw reassembly still sets up 'StreamMsg' objects for content inspection. They are set up based on either the full StreamingBuffer, or based on the StreamingBufferBlocks if there are gaps in the data. Reworked 'stream needs work' logic. When a flow times out the flow engine checks whether a TCP flow still needs work. The StreamNeedsReassembly function is used to test if a stream still has unreassembled segments or uninspected stream chunks. This patch updates the function to consider the app and/or raw progress. It also cleans the function up and adds more meaningful debug messages. Finally it makes it non-inline. Unittests have been overhauled, and partly moved into their own files. Remove lots of dead code.
10 years ago
TCP_SEG_LEN(ssn->client.seg_list_tail));
}
}
if (FLOW_IS_IPV4(f)) {
p->tcph->th_sum = TCPChecksum(p->ip4h->s_ip_addrs,
(uint16_t *)p->tcph, 20, 0);
/* calc ipv4 csum as we may log it and barnyard might reject
* a wrong checksum */
p->ip4h->ip_csum = IPV4Checksum((uint16_t *)p->ip4h,
IPV4_GET_RAW_HLEN(p->ip4h), 0);
} else if (FLOW_IS_IPV6(f)) {
p->tcph->th_sum = TCPChecksum(p->ip6h->s_ip6_addrs,
(uint16_t *)p->tcph, 20, 0);
}
memset(&p->ts, 0, sizeof(struct timeval));
TimeGet(&p->ts);
App layer API rewritten. The main files in question are: app-layer.[ch], app-layer-detect-proto.[ch] and app-layer-parser.[ch]. Things addressed in this commit: - Brings out a proper separation between protocol detection phase and the parser phase. - The dns app layer now is registered such that we don't use "dnstcp" and "dnsudp" in the rules. A user who previously wrote a rule like this - "alert dnstcp....." or "alert dnsudp....." would now have to use, alert dns (ipproto:tcp;) or alert udp (app-layer-protocol:dns;) or alert ip (ipproto:udp; app-layer-protocol:dns;) The same rules extend to other another such protocol, dcerpc. - The app layer parser api now takes in the ipproto while registering callbacks. - The app inspection/detection engine also takes an ipproto. - All app layer parser functions now take direction as STREAM_TOSERVER or STREAM_TOCLIENT, as opposed to 0 or 1, which was taken by some of the functions. - FlowInitialize() and FlowRecycle() now resets proto to 0. This is needed by unittests, which would try to clean the flow, and that would call the api, AppLayerParserCleanupParserState(), which would try to clean the app state, but the app layer now needs an ipproto to figure out which api to internally call to clean the state, and if the ipproto is 0, it would return without trying to clean the state. - A lot of unittests are now updated where if they are using a flow and they need to use the app layer, we would set a flow ipproto. - The "app-layer" section in the yaml conf has also been updated as well.
12 years ago
AppLayerParserSetEOF(f->alparser);
return p;
error:
FlowDeReference(&p->flow);
return NULL;
}
static inline Packet *FlowForceReassemblyPseudoPacketGet(int direction,
Flow *f,
TcpSession *ssn,
int dummy)
{
PacketPoolWait();
Packet *p = PacketPoolGetPacket();
if (p == NULL) {
return NULL;
}
PACKET_PROFILING_START(p);
return FlowForceReassemblyPseudoPacketSetup(p, direction, f, ssn, dummy);
}
/**
* \brief Check if a flow needs forced reassembly, or any other processing
*
* \param f *LOCKED* flow
* \param server ptr to int that should be set to 1 or 2 if we return 1
* \param client ptr to int that should be set to 1 or 2 if we return 1
*
* \retval 0 no
* \retval 1 yes
*/
int FlowForceReassemblyNeedReassembly(Flow *f, int *server, int *client)
{
TcpSession *ssn;
if (f == NULL) {
*server = *client = STREAM_HAS_UNPROCESSED_SEGMENTS_NONE;
SCReturnInt(0);
}
/* Get the tcp session for the flow */
ssn = (TcpSession *)f->protoctx;
if (ssn == NULL) {
*server = *client = STREAM_HAS_UNPROCESSED_SEGMENTS_NONE;
SCReturnInt(0);
}
*client = StreamNeedsReassembly(ssn, STREAM_TOSERVER);
*server = StreamNeedsReassembly(ssn, STREAM_TOCLIENT);
/* if state is not fully closed we assume that we haven't fully
* inspected the app layer state yet */
if (ssn->state >= TCP_ESTABLISHED && ssn->state != TCP_CLOSED)
{
*client = STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION;
*server = STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION;
}
/* if app layer still needs some love, push through */
if (f->alproto != ALPROTO_UNKNOWN && f->alstate != NULL &&
App layer API rewritten. The main files in question are: app-layer.[ch], app-layer-detect-proto.[ch] and app-layer-parser.[ch]. Things addressed in this commit: - Brings out a proper separation between protocol detection phase and the parser phase. - The dns app layer now is registered such that we don't use "dnstcp" and "dnsudp" in the rules. A user who previously wrote a rule like this - "alert dnstcp....." or "alert dnsudp....." would now have to use, alert dns (ipproto:tcp;) or alert udp (app-layer-protocol:dns;) or alert ip (ipproto:udp; app-layer-protocol:dns;) The same rules extend to other another such protocol, dcerpc. - The app layer parser api now takes in the ipproto while registering callbacks. - The app inspection/detection engine also takes an ipproto. - All app layer parser functions now take direction as STREAM_TOSERVER or STREAM_TOCLIENT, as opposed to 0 or 1, which was taken by some of the functions. - FlowInitialize() and FlowRecycle() now resets proto to 0. This is needed by unittests, which would try to clean the flow, and that would call the api, AppLayerParserCleanupParserState(), which would try to clean the app state, but the app layer now needs an ipproto to figure out which api to internally call to clean the state, and if the ipproto is 0, it would return without trying to clean the state. - A lot of unittests are now updated where if they are using a flow and they need to use the app layer, we would set a flow ipproto. - The "app-layer" section in the yaml conf has also been updated as well.
12 years ago
AppLayerParserProtocolSupportsTxs(f->proto, f->alproto))
{
uint64_t total_txs = AppLayerParserGetTxCnt(f, f->alstate);
if (AppLayerParserGetTransactionActive(f, f->alparser, STREAM_TOCLIENT) < total_txs)
App layer API rewritten. The main files in question are: app-layer.[ch], app-layer-detect-proto.[ch] and app-layer-parser.[ch]. Things addressed in this commit: - Brings out a proper separation between protocol detection phase and the parser phase. - The dns app layer now is registered such that we don't use "dnstcp" and "dnsudp" in the rules. A user who previously wrote a rule like this - "alert dnstcp....." or "alert dnsudp....." would now have to use, alert dns (ipproto:tcp;) or alert udp (app-layer-protocol:dns;) or alert ip (ipproto:udp; app-layer-protocol:dns;) The same rules extend to other another such protocol, dcerpc. - The app layer parser api now takes in the ipproto while registering callbacks. - The app inspection/detection engine also takes an ipproto. - All app layer parser functions now take direction as STREAM_TOSERVER or STREAM_TOCLIENT, as opposed to 0 or 1, which was taken by some of the functions. - FlowInitialize() and FlowRecycle() now resets proto to 0. This is needed by unittests, which would try to clean the flow, and that would call the api, AppLayerParserCleanupParserState(), which would try to clean the app state, but the app layer now needs an ipproto to figure out which api to internally call to clean the state, and if the ipproto is 0, it would return without trying to clean the state. - A lot of unittests are now updated where if they are using a flow and they need to use the app layer, we would set a flow ipproto. - The "app-layer" section in the yaml conf has also been updated as well.
12 years ago
{
*server = STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION;
}
if (AppLayerParserGetTransactionActive(f, f->alparser, STREAM_TOSERVER) < total_txs)
App layer API rewritten. The main files in question are: app-layer.[ch], app-layer-detect-proto.[ch] and app-layer-parser.[ch]. Things addressed in this commit: - Brings out a proper separation between protocol detection phase and the parser phase. - The dns app layer now is registered such that we don't use "dnstcp" and "dnsudp" in the rules. A user who previously wrote a rule like this - "alert dnstcp....." or "alert dnsudp....." would now have to use, alert dns (ipproto:tcp;) or alert udp (app-layer-protocol:dns;) or alert ip (ipproto:udp; app-layer-protocol:dns;) The same rules extend to other another such protocol, dcerpc. - The app layer parser api now takes in the ipproto while registering callbacks. - The app inspection/detection engine also takes an ipproto. - All app layer parser functions now take direction as STREAM_TOSERVER or STREAM_TOCLIENT, as opposed to 0 or 1, which was taken by some of the functions. - FlowInitialize() and FlowRecycle() now resets proto to 0. This is needed by unittests, which would try to clean the flow, and that would call the api, AppLayerParserCleanupParserState(), which would try to clean the app state, but the app layer now needs an ipproto to figure out which api to internally call to clean the state, and if the ipproto is 0, it would return without trying to clean the state. - A lot of unittests are now updated where if they are using a flow and they need to use the app layer, we would set a flow ipproto. - The "app-layer" section in the yaml conf has also been updated as well.
12 years ago
{
*client = STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION;
}
}
/* nothing to do */
if (*client == STREAM_HAS_UNPROCESSED_SEGMENTS_NONE &&
*server == STREAM_HAS_UNPROCESSED_SEGMENTS_NONE) {
SCReturnInt(0);
}
SCReturnInt(1);
}
/**
* \internal
* \brief Forces reassembly for flow if it needs it.
*
* The function requires flow to be locked beforehand.
*
* \param f Pointer to the flow.
* \param server action required for server: 1 or 2
* \param client action required for client: 1 or 2
*
* \retval 0 This flow doesn't need any reassembly processing; 1 otherwise.
*/
int FlowForceReassemblyForFlow(Flow *f, int server, int client)
{
Packet *p1 = NULL, *p2 = NULL;
TcpSession *ssn;
/* looks like we have no flows in this queue */
if (f == NULL) {
return 0;
}
/* Get the tcp session for the flow */
ssn = (TcpSession *)f->protoctx;
if (ssn == NULL) {
return 0;
}
/* The packets we use are based on what segments in what direction are
* unprocessed.
* p1 if we have client segments for reassembly purpose only. If we
* have no server segments p2 can be a toserver packet with dummy
* seq/ack, and if we have server segments p2 has to carry out reassembly
* for server segment as well, in which case we will also need a p3 in the
* toclient which is now dummy since all we need it for is detection */
/* insert a pseudo packet in the toserver direction */
if (client == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION) {
p1 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 1);
if (p1 == NULL) {
goto done;
}
PKT_SET_SRC(p1, PKT_SRC_FFR);
if (server == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION) {
p2 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1);
if (p2 == NULL) {
FlowDeReference(&p1->flow);
TmqhOutputPacketpool(NULL, p1);
goto done;
}
PKT_SET_SRC(p2, PKT_SRC_FFR);
}
} else {
if (server == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION) {
p1 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1);
if (p1 == NULL) {
goto done;
}
PKT_SET_SRC(p1, PKT_SRC_FFR);
} else {
/* impossible */
BUG_ON(1);
}
}
/* inject the packet(s) into the appropriate thread */
int thread_id = (int)f->thread_id;
Packet *packets[3] = { p1, p2 ? p2 : NULL, NULL }; /**< null terminated array of packets */
if (unlikely(!(TmThreadsInjectPacketsById(packets, thread_id)))) {
FlowDeReference(&p1->flow);
TmqhOutputPacketpool(NULL, p1);
if (p2) {
FlowDeReference(&p2->flow);
TmqhOutputPacketpool(NULL, p2);
}
}
/* done, in case of error (no packet) we still tag flow as complete
* as we're probably resource stress if we couldn't get packets */
done:
f->flags |= FLOW_TIMEOUT_REASSEMBLY_DONE;
return 1;
}
/**
* \internal
* \brief Forces reassembly for flows that need it.
*
* When this function is called we're running in virtually dead engine,
* so locking the flows is not strictly required. The reasons it is still
* done are:
* - code consistency
* - silence complaining profilers
* - allow us to aggressively check using debug valdation assertions
* - be robust in case of future changes
* - locking overhead if neglectable when no other thread fights us
*
* \param q The queue to process flows from.
*/
static inline void FlowForceReassemblyForHash(void)
{
Flow *f;
TcpSession *ssn;
int client_ok = 0;
int server_ok = 0;
uint32_t idx = 0;
for (idx = 0; idx < flow_config.hash_size; idx++) {
FlowBucket *fb = &flow_hash[idx];
PacketPoolWaitForN(9);
FBLOCK_LOCK(fb);
/* get the topmost flow from the QUEUE */
f = fb->head;
/* we need to loop through all the flows in the queue */
while (f != NULL) {
PacketPoolWaitForN(3);
FLOWLOCK_WRLOCK(f);
/* Get the tcp session for the flow */
ssn = (TcpSession *)f->protoctx;
/* \todo Also skip flows that shouldn't be inspected */
if (ssn == NULL) {
FLOWLOCK_UNLOCK(f);
f = f->hnext;
continue;
}
if (FlowForceReassemblyNeedReassembly(f, &server_ok, &client_ok) == 1) {
FlowForceReassemblyForFlow(f, server_ok, client_ok);
}
FLOWLOCK_UNLOCK(f);
/* next flow in the queue */
f = f->hnext;
}
FBLOCK_UNLOCK(fb);
}
return;
}
/**
* \brief Force reassembly for all the flows that have unprocessed segments.
*/
void FlowForceReassembly(void)
{
/* Carry out flow reassembly for unattended flows */
FlowForceReassemblyForHash();
return;
}