aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/suricata/src/flow-timeout.c
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/suricata/src/flow-timeout.c')
-rw-r--r--framework/src/suricata/src/flow-timeout.c572
1 files changed, 0 insertions, 572 deletions
diff --git a/framework/src/suricata/src/flow-timeout.c b/framework/src/suricata/src/flow-timeout.c
deleted file mode 100644
index 8df85cdd..00000000
--- a/framework/src/suricata/src/flow-timeout.c
+++ /dev/null
@@ -1,572 +0,0 @@
-/* Copyright (C) 2007-2012 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 "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"
-#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) {
- return NULL;
- }
- }
- /* 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) {
- return NULL;
- }
- }
- /* 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 +
- ssn->server.seg_list_tail->payload_len);
- }
-
- /* 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 +
- ssn->client.seg_list_tail->payload_len);
- }
- }
-
- if (FLOW_IS_IPV4(f)) {
- p->tcph->th_sum = TCPCalculateChecksum(p->ip4h->s_ip_addrs,
- (uint16_t *)p->tcph, 20);
- /* calc ipv4 csum as we may log it and barnyard might reject
- * a wrong checksum */
- p->ip4h->ip_csum = IPV4CalculateChecksum((uint16_t *)p->ip4h,
- IPV4_GET_RAW_HLEN(p->ip4h));
- } else if (FLOW_IS_IPV6(f)) {
- p->tcph->th_sum = TCPCalculateChecksum(p->ip6h->s_ip6_addrs,
- (uint16_t *)p->tcph, 20);
- }
-
- memset(&p->ts, 0, sizeof(struct timeval));
- TimeGet(&p->ts);
-
- AppLayerParserSetEOF(f->alparser);
-
- return p;
-}
-
-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, 0);
- *server = StreamNeedsReassembly(ssn, 1);
-
- /* 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)
- {
- if (*client != STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY)
- *client = STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION;
-
- if (*server != STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY)
- *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 &&
- AppLayerParserProtocolSupportsTxs(f->proto, f->alproto))
- {
- uint64_t total_txs = AppLayerParserGetTxCnt(f->proto, f->alproto, f->alstate);
-
- if (AppLayerParserGetTransactionActive(f->proto, f->alproto,
- f->alparser, STREAM_TOCLIENT) < total_txs)
- {
- if (*server != STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY)
- *server = STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION;
- }
- if (AppLayerParserGetTransactionActive(f->proto, f->alproto,
- f->alparser, STREAM_TOSERVER) < total_txs)
- {
- if (*client != STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY)
- *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, *p3 = 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_REASSEMBLY) {
- p1 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 0);
- if (p1 == NULL) {
- goto done;
- }
- PKT_SET_SRC(p1, PKT_SRC_FFR);
-
- if (server == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY) {
- p2 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 0);
- if (p2 == NULL) {
- FlowDeReference(&p1->flow);
- TmqhOutputPacketpool(NULL, p1);
- goto done;
- }
- PKT_SET_SRC(p2, PKT_SRC_FFR);
-
- p3 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1);
- if (p3 == NULL) {
- FlowDeReference(&p1->flow);
- TmqhOutputPacketpool(NULL, p1);
- FlowDeReference(&p2->flow);
- TmqhOutputPacketpool(NULL, p2);
- goto done;
- }
- PKT_SET_SRC(p3, PKT_SRC_FFR);
- } else {
- p2 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 1);
- if (p2 == NULL) {
- FlowDeReference(&p1->flow);
- TmqhOutputPacketpool(NULL, p1);
- goto done;
- }
- PKT_SET_SRC(p2, PKT_SRC_FFR);
- }
-
- } else if (client == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION) {
- if (server == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY) {
- p1 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 0);
- if (p1 == NULL) {
- goto done;
- }
- PKT_SET_SRC(p1, PKT_SRC_FFR);
-
- 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 {
- 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_REASSEMBLY) {
- p1 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 0);
- if (p1 == NULL) {
- goto done;
- }
- PKT_SET_SRC(p1, PKT_SRC_FFR);
-
- 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[4] = { p1, p2 ? p2 : p3, p2 ? p3 : 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);
- }
- if (p3) {
- FlowDeReference(&p3->flow);
- TmqhOutputPacketpool(NULL, p3);
- }
- }
-
- /* 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;
-}
-