mirror of https://github.com/OISF/suricata
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.
498 lines
16 KiB
C
498 lines
16 KiB
C
/* 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 Victor Julien <victor@inliniac.net>
|
|
*/
|
|
|
|
#ifndef __FLOW_H__
|
|
#define __FLOW_H__
|
|
|
|
#include "decode.h"
|
|
#include "util-var.h"
|
|
#include "util-atomic.h"
|
|
#include "detect-tag.h"
|
|
|
|
#define FLOW_QUIET TRUE
|
|
#define FLOW_VERBOSE FALSE
|
|
|
|
#define TOSERVER 0
|
|
#define TOCLIENT 1
|
|
|
|
/* per flow flags */
|
|
|
|
/** At least on packet from the source address was seen */
|
|
#define FLOW_TO_SRC_SEEN 0x00000001
|
|
/** At least on packet from the destination address was seen */
|
|
#define FLOW_TO_DST_SEEN 0x00000002
|
|
|
|
// vacany 1x
|
|
|
|
/** no magic on files in this flow */
|
|
#define FLOW_FILE_NO_MAGIC_TS 0x00000008
|
|
#define FLOW_FILE_NO_MAGIC_TC 0x00000010
|
|
|
|
/** Flow was inspected against IP-Only sigs in the toserver direction */
|
|
#define FLOW_TOSERVER_IPONLY_SET 0x00000020
|
|
/** Flow was inspected against IP-Only sigs in the toclient direction */
|
|
#define FLOW_TOCLIENT_IPONLY_SET 0x00000040
|
|
|
|
/** Packet belonging to this flow should not be inspected at all */
|
|
#define FLOW_NOPACKET_INSPECTION 0x00000080
|
|
/** Packet payloads belonging to this flow should not be inspected */
|
|
#define FLOW_NOPAYLOAD_INSPECTION 0x00000100
|
|
|
|
/** All packets in this flow should be dropped */
|
|
#define FLOW_ACTION_DROP 0x00000200
|
|
|
|
/** Sgh for toserver direction set (even if it's NULL) */
|
|
#define FLOW_SGH_TOSERVER 0x00000800
|
|
/** Sgh for toclient direction set (even if it's NULL) */
|
|
#define FLOW_SGH_TOCLIENT 0x00001000
|
|
|
|
/** packet to server direction has been logged in drop file (only in IPS mode) */
|
|
#define FLOW_TOSERVER_DROP_LOGGED 0x00002000
|
|
/** packet to client direction has been logged in drop file (only in IPS mode) */
|
|
#define FLOW_TOCLIENT_DROP_LOGGED 0x00004000
|
|
/** alproto detect done. Right now we need it only for udp */
|
|
#define FLOW_ALPROTO_DETECT_DONE 0x00008000
|
|
#define FLOW_NO_APPLAYER_INSPECTION 0x00010000
|
|
|
|
/** Pattern matcher alproto detection done */
|
|
#define FLOW_TS_PM_ALPROTO_DETECT_DONE 0x00020000
|
|
/** Probing parser alproto detection done */
|
|
#define FLOW_TS_PP_ALPROTO_DETECT_DONE 0x00040000
|
|
/** Both pattern matcher and probing parser alproto detection done */
|
|
#define FLOW_TS_PM_PP_ALPROTO_DETECT_DONE 0x00080000
|
|
/** Pattern matcher alproto detection done */
|
|
#define FLOW_TC_PM_ALPROTO_DETECT_DONE 0x00100000
|
|
/** Probing parser alproto detection done */
|
|
#define FLOW_TC_PP_ALPROTO_DETECT_DONE 0x00200000
|
|
/** Both pattern matcher and probing parser alproto detection done */
|
|
#define FLOW_TC_PM_PP_ALPROTO_DETECT_DONE 0x00400000
|
|
#define FLOW_TIMEOUT_REASSEMBLY_DONE 0x00800000
|
|
/** even if the flow has files, don't store 'm */
|
|
#define FLOW_FILE_NO_STORE_TS 0x01000000
|
|
#define FLOW_FILE_NO_STORE_TC 0x02000000
|
|
|
|
/** flow is ipv4 */
|
|
#define FLOW_IPV4 0x04000000
|
|
/** flow is ipv6 */
|
|
#define FLOW_IPV6 0x08000000
|
|
|
|
/** no md5 on files in this flow */
|
|
#define FLOW_FILE_NO_MD5_TS 0x10000000
|
|
#define FLOW_FILE_NO_MD5_TC 0x20000000
|
|
|
|
/** no size tracking of files in this flow */
|
|
#define FLOW_FILE_NO_SIZE_TS 0x40000000
|
|
#define FLOW_FILE_NO_SIZE_TC 0x80000000
|
|
|
|
#define FLOW_IS_IPV4(f) \
|
|
(((f)->flags & FLOW_IPV4) == FLOW_IPV4)
|
|
#define FLOW_IS_IPV6(f) \
|
|
(((f)->flags & FLOW_IPV6) == FLOW_IPV6)
|
|
|
|
#define FLOW_COPY_IPV4_ADDR_TO_PACKET(fa, pa) do { \
|
|
(pa)->family = AF_INET; \
|
|
(pa)->addr_data32[0] = (fa)->addr_data32[0]; \
|
|
} while (0)
|
|
|
|
#define FLOW_COPY_IPV6_ADDR_TO_PACKET(fa, pa) do { \
|
|
(pa)->family = AF_INET; \
|
|
(pa)->addr_data32[0] = (fa)->addr_data32[0]; \
|
|
(pa)->addr_data32[1] = (fa)->addr_data32[1]; \
|
|
(pa)->addr_data32[2] = (fa)->addr_data32[2]; \
|
|
(pa)->addr_data32[3] = (fa)->addr_data32[3]; \
|
|
} while (0)
|
|
|
|
/* Set the IPv4 addressesinto the Addrs of the Packet.
|
|
* Make sure p->ip4h is initialized and validated.
|
|
*
|
|
* We set the rest of the struct to 0 so we can
|
|
* prevent using memset. */
|
|
#define FLOW_SET_IPV4_SRC_ADDR_FROM_PACKET(p, a) do { \
|
|
(a)->addr_data32[0] = (uint32_t)(p)->ip4h->s_ip_src.s_addr; \
|
|
(a)->addr_data32[1] = 0; \
|
|
(a)->addr_data32[2] = 0; \
|
|
(a)->addr_data32[3] = 0; \
|
|
} while (0)
|
|
|
|
#define FLOW_SET_IPV4_DST_ADDR_FROM_PACKET(p, a) do { \
|
|
(a)->addr_data32[0] = (uint32_t)(p)->ip4h->s_ip_dst.s_addr; \
|
|
(a)->addr_data32[1] = 0; \
|
|
(a)->addr_data32[2] = 0; \
|
|
(a)->addr_data32[3] = 0; \
|
|
} while (0)
|
|
|
|
/* clear the address structure by setting all fields to 0 */
|
|
#define FLOW_CLEAR_ADDR(a) do { \
|
|
(a)->addr_data32[0] = 0; \
|
|
(a)->addr_data32[1] = 0; \
|
|
(a)->addr_data32[2] = 0; \
|
|
(a)->addr_data32[3] = 0; \
|
|
} while (0)
|
|
|
|
/* Set the IPv6 addressesinto the Addrs of the Packet.
|
|
* Make sure p->ip6h is initialized and validated. */
|
|
#define FLOW_SET_IPV6_SRC_ADDR_FROM_PACKET(p, a) do { \
|
|
(a)->addr_data32[0] = (p)->ip6h->s_ip6_src[0]; \
|
|
(a)->addr_data32[1] = (p)->ip6h->s_ip6_src[1]; \
|
|
(a)->addr_data32[2] = (p)->ip6h->s_ip6_src[2]; \
|
|
(a)->addr_data32[3] = (p)->ip6h->s_ip6_src[3]; \
|
|
} while (0)
|
|
|
|
#define FLOW_SET_IPV6_DST_ADDR_FROM_PACKET(p, a) do { \
|
|
(a)->addr_data32[0] = (p)->ip6h->s_ip6_dst[0]; \
|
|
(a)->addr_data32[1] = (p)->ip6h->s_ip6_dst[1]; \
|
|
(a)->addr_data32[2] = (p)->ip6h->s_ip6_dst[2]; \
|
|
(a)->addr_data32[3] = (p)->ip6h->s_ip6_dst[3]; \
|
|
} while (0)
|
|
|
|
/* pkt flow flags */
|
|
#define FLOW_PKT_TOSERVER 0x01
|
|
#define FLOW_PKT_TOCLIENT 0x02
|
|
#define FLOW_PKT_ESTABLISHED 0x04
|
|
#define FLOW_PKT_STATELESS 0x08
|
|
#define FLOW_PKT_TOSERVER_IPONLY_SET 0x10
|
|
#define FLOW_PKT_TOCLIENT_IPONLY_SET 0x20
|
|
/** \todo only used by flow keyword internally. */
|
|
#define FLOW_PKT_NOSTREAM 0x40
|
|
/** \todo only used by flow keyword internally. */
|
|
#define FLOW_PKT_ONLYSTREAM 0x80
|
|
|
|
/** Mutex or RWLocks for the flow. */
|
|
//#define FLOWLOCK_RWLOCK
|
|
#define FLOWLOCK_MUTEX
|
|
|
|
#ifdef FLOWLOCK_RWLOCK
|
|
#ifdef FLOWLOCK_MUTEX
|
|
#error Cannot enable both FLOWLOCK_RWLOCK and FLOWLOCK_MUTEX
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef FLOWLOCK_RWLOCK
|
|
#define FLOWLOCK_INIT(fb) SCRWLockInit(&(fb)->r, NULL)
|
|
#define FLOWLOCK_DESTROY(fb) SCRWLockDestroy(&(fb)->r)
|
|
#define FLOWLOCK_RDLOCK(fb) SCRWLockRDLock(&(fb)->r)
|
|
#define FLOWLOCK_WRLOCK(fb) SCRWLockWRLock(&(fb)->r)
|
|
#define FLOWLOCK_TRYRDLOCK(fb) SCRWLockTryRDLock(&(fb)->r)
|
|
#define FLOWLOCK_TRYWRLOCK(fb) SCRWLockTryWRLock(&(fb)->r)
|
|
#define FLOWLOCK_UNLOCK(fb) SCRWLockUnlock(&(fb)->r)
|
|
#elif defined FLOWLOCK_MUTEX
|
|
#define FLOWLOCK_INIT(fb) SCMutexInit(&(fb)->m, NULL)
|
|
#define FLOWLOCK_DESTROY(fb) SCMutexDestroy(&(fb)->m)
|
|
#define FLOWLOCK_RDLOCK(fb) SCMutexLock(&(fb)->m)
|
|
#define FLOWLOCK_WRLOCK(fb) SCMutexLock(&(fb)->m)
|
|
#define FLOWLOCK_TRYRDLOCK(fb) SCMutexTrylock(&(fb)->m)
|
|
#define FLOWLOCK_TRYWRLOCK(fb) SCMutexTrylock(&(fb)->m)
|
|
#define FLOWLOCK_UNLOCK(fb) SCMutexUnlock(&(fb)->m)
|
|
#else
|
|
#error Enable FLOWLOCK_RWLOCK or FLOWLOCK_MUTEX
|
|
#endif
|
|
|
|
/* global flow config */
|
|
typedef struct FlowCnf_
|
|
{
|
|
uint32_t hash_rand;
|
|
uint32_t hash_size;
|
|
uint64_t memcap;
|
|
uint32_t max_flows;
|
|
uint32_t prealloc;
|
|
|
|
uint32_t timeout_new;
|
|
uint32_t timeout_est;
|
|
|
|
uint32_t emerg_timeout_new;
|
|
uint32_t emerg_timeout_est;
|
|
uint32_t emergency_recovery;
|
|
|
|
} FlowConfig;
|
|
|
|
/* Hash key for the flow hash */
|
|
typedef struct FlowKey_
|
|
{
|
|
Address src, dst;
|
|
Port sp, dp;
|
|
uint8_t proto;
|
|
uint8_t recursion_level;
|
|
|
|
} FlowKey;
|
|
|
|
typedef struct FlowAddress_ {
|
|
union {
|
|
uint32_t address_un_data32[4]; /* type-specific field */
|
|
uint16_t address_un_data16[8]; /* type-specific field */
|
|
uint8_t address_un_data8[16]; /* type-specific field */
|
|
} address;
|
|
} FlowAddress;
|
|
|
|
#define addr_data32 address.address_un_data32
|
|
#define addr_data16 address.address_un_data16
|
|
#define addr_data8 address.address_un_data8
|
|
|
|
/**
|
|
* \brief Flow data structure.
|
|
*
|
|
* The flow is a global data structure that is created for new packets of a
|
|
* flow and then looked up for the following packets of a flow.
|
|
*
|
|
* Locking
|
|
*
|
|
* The flow is updated/used by multiple packets at the same time. This is why
|
|
* there is a flow-mutex. It's a mutex and not a spinlock because some
|
|
* operations on the flow can be quite expensive, thus spinning would be
|
|
* too expensive.
|
|
*
|
|
* The flow "header" (addresses, ports, proto, recursion level) are static
|
|
* after the initialization and remain read-only throughout the entire live
|
|
* of a flow. This is why we can access those without protection of the lock.
|
|
*/
|
|
|
|
typedef struct Flow_
|
|
{
|
|
/* flow "header", used for hashing and flow lookup. Static after init,
|
|
* so safe to look at without lock */
|
|
FlowAddress src, dst;
|
|
union {
|
|
Port sp; /**< tcp/udp source port */
|
|
uint8_t type; /**< icmp type */
|
|
};
|
|
union {
|
|
Port dp; /**< tcp/udp destination port */
|
|
uint8_t code; /**< icmp code */
|
|
};
|
|
uint8_t proto;
|
|
uint8_t recursion_level;
|
|
uint16_t vlan_id[2];
|
|
|
|
/* end of flow "header" */
|
|
|
|
/** how many pkts and stream msgs are using the flow *right now*. This
|
|
* variable is atomic so not protected by the Flow mutex "m".
|
|
*
|
|
* On receiving a packet the counter is incremented while the flow
|
|
* bucked is locked, which is also the case on timeout pruning.
|
|
*/
|
|
SC_ATOMIC_DECLARE(unsigned short, use_cnt);
|
|
|
|
/** flow queue id, used with autofp */
|
|
SC_ATOMIC_DECLARE(int, autofp_tmqh_flow_qid);
|
|
|
|
uint32_t probing_parser_toserver_al_proto_masks;
|
|
uint32_t probing_parser_toclient_al_proto_masks;
|
|
|
|
uint32_t flags;
|
|
|
|
/* ts of flow init and last update */
|
|
int32_t lastts_sec;
|
|
|
|
#ifdef FLOWLOCK_RWLOCK
|
|
SCRWLock r;
|
|
#elif defined FLOWLOCK_MUTEX
|
|
SCMutex m;
|
|
#else
|
|
#error Enable FLOWLOCK_RWLOCK or FLOWLOCK_MUTEX
|
|
#endif
|
|
|
|
/** protocol specific data pointer, e.g. for TcpSession */
|
|
void *protoctx;
|
|
|
|
/** mapping to Flow's protocol specific protocols for timeouts
|
|
and state and free functions. */
|
|
uint8_t protomap;
|
|
uint8_t pad0;
|
|
|
|
uint16_t alproto; /**< \brief application level protocol */
|
|
|
|
/** detection engine ctx id used to inspect this flow. Set at initial
|
|
* inspection. If it doesn't match the currently in use de_ctx, the
|
|
* de_state and stored sgh ptrs are reset. */
|
|
uint32_t de_ctx_id;
|
|
|
|
/** application level storage ptrs.
|
|
*
|
|
*/
|
|
void *alparser; /**< parser internal state */
|
|
void *alstate; /**< application layer state */
|
|
|
|
/** detection engine state */
|
|
struct DetectEngineState_ *de_state;
|
|
|
|
/** toclient sgh for this flow. Only use when FLOW_SGH_TOCLIENT flow flag
|
|
* has been set. */
|
|
struct SigGroupHead_ *sgh_toclient;
|
|
/** toserver sgh for this flow. Only use when FLOW_SGH_TOSERVER flow flag
|
|
* has been set. */
|
|
struct SigGroupHead_ *sgh_toserver;
|
|
|
|
/* pointer to the var list */
|
|
GenericVar *flowvar;
|
|
|
|
SCMutex de_state_m; /**< mutex lock for the de_state object */
|
|
|
|
/** hash list pointers, protected by fb->s */
|
|
struct Flow_ *hnext; /* hash list */
|
|
struct Flow_ *hprev;
|
|
struct FlowBucket_ *fb;
|
|
|
|
/** queue list pointers, protected by queue mutex */
|
|
struct Flow_ *lnext; /* list */
|
|
struct Flow_ *lprev;
|
|
struct timeval startts;
|
|
#ifdef DEBUG
|
|
uint32_t todstpktcnt;
|
|
uint32_t tosrcpktcnt;
|
|
uint64_t bytecnt;
|
|
#endif
|
|
} Flow;
|
|
|
|
enum {
|
|
FLOW_STATE_NEW = 0,
|
|
FLOW_STATE_ESTABLISHED,
|
|
FLOW_STATE_CLOSED,
|
|
};
|
|
|
|
typedef struct FlowProto_ {
|
|
uint32_t new_timeout;
|
|
uint32_t est_timeout;
|
|
uint32_t closed_timeout;
|
|
uint32_t emerg_new_timeout;
|
|
uint32_t emerg_est_timeout;
|
|
uint32_t emerg_closed_timeout;
|
|
void (*Freefunc)(void *);
|
|
int (*GetProtoState)(void *);
|
|
} FlowProto;
|
|
|
|
void FlowHandlePacket (ThreadVars *, Packet *);
|
|
void FlowInitConfig (char);
|
|
void FlowPrintQueueInfo (void);
|
|
void FlowShutdown(void);
|
|
void FlowSetIPOnlyFlag(Flow *, char);
|
|
void FlowSetIPOnlyFlagNoLock(Flow *, char);
|
|
|
|
void FlowIncrUsecnt(Flow *);
|
|
void FlowDecrUsecnt(Flow *);
|
|
|
|
void FlowRegisterTests (void);
|
|
int FlowSetProtoTimeout(uint8_t ,uint32_t ,uint32_t ,uint32_t);
|
|
int FlowSetProtoEmergencyTimeout(uint8_t ,uint32_t ,uint32_t ,uint32_t);
|
|
int FlowSetProtoFreeFunc (uint8_t , void (*Free)(void *));
|
|
int FlowSetFlowStateFunc (uint8_t , int (*GetProtoState)(void *));
|
|
void FlowUpdateQueue(Flow *);
|
|
|
|
struct FlowQueue_;
|
|
|
|
int FlowUpdateSpareFlows(void);
|
|
|
|
static inline void FlowLockSetNoPacketInspectionFlag(Flow *);
|
|
static inline void FlowSetNoPacketInspectionFlag(Flow *);
|
|
static inline void FlowLockSetNoPayloadInspectionFlag(Flow *);
|
|
static inline void FlowSetNoPayloadInspectionFlag(Flow *);
|
|
static inline void FlowSetSessionNoApplayerInspectionFlag(Flow *);
|
|
|
|
int FlowGetPacketDirection(Flow *, Packet *);
|
|
|
|
void FlowCleanupAppLayer(Flow *);
|
|
|
|
/** ----- Inline functions ----- */
|
|
|
|
/** \brief Set the No Packet Inspection Flag after locking the flow.
|
|
*
|
|
* \param f Flow to set the flag in
|
|
*/
|
|
static inline void FlowLockSetNoPacketInspectionFlag(Flow *f) {
|
|
SCEnter();
|
|
|
|
SCLogDebug("flow %p", f);
|
|
FLOWLOCK_WRLOCK(f);
|
|
f->flags |= FLOW_NOPACKET_INSPECTION;
|
|
FLOWLOCK_UNLOCK(f);
|
|
|
|
SCReturn;
|
|
}
|
|
|
|
/** \brief Set the No Packet Inspection Flag without locking the flow.
|
|
*
|
|
* \param f Flow to set the flag in
|
|
*/
|
|
static inline void FlowSetNoPacketInspectionFlag(Flow *f) {
|
|
SCEnter();
|
|
|
|
SCLogDebug("flow %p", f);
|
|
f->flags |= FLOW_NOPACKET_INSPECTION;
|
|
|
|
SCReturn;
|
|
}
|
|
|
|
/** \brief Set the No payload inspection Flag after locking the flow.
|
|
*
|
|
* \param f Flow to set the flag in
|
|
*/
|
|
static inline void FlowLockSetNoPayloadInspectionFlag(Flow *f) {
|
|
SCEnter();
|
|
|
|
SCLogDebug("flow %p", f);
|
|
FLOWLOCK_WRLOCK(f);
|
|
f->flags |= FLOW_NOPAYLOAD_INSPECTION;
|
|
FLOWLOCK_UNLOCK(f);
|
|
|
|
SCReturn;
|
|
}
|
|
|
|
/** \brief Set the No payload inspection Flag without locking the flow.
|
|
*
|
|
* \param f Flow to set the flag in
|
|
*/
|
|
static inline void FlowSetNoPayloadInspectionFlag(Flow *f) {
|
|
SCEnter();
|
|
|
|
SCLogDebug("flow %p", f);
|
|
f->flags |= FLOW_NOPAYLOAD_INSPECTION;
|
|
|
|
SCReturn;
|
|
}
|
|
|
|
/** \brief set flow flag to disable app layer inspection
|
|
*
|
|
* \param f *LOCKED* flow
|
|
*/
|
|
static inline void FlowSetSessionNoApplayerInspectionFlag(Flow *f) {
|
|
f->flags |= FLOW_NO_APPLAYER_INSPECTION;
|
|
}
|
|
|
|
#define FlowReference(dst_f_ptr, f) do { \
|
|
if ((f) != NULL) { \
|
|
FlowIncrUsecnt((f)); \
|
|
*(dst_f_ptr) = f; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define FlowDeReference(src_f_ptr) do { \
|
|
if (*(src_f_ptr) != NULL) { \
|
|
FlowDecrUsecnt(*(src_f_ptr)); \
|
|
*(src_f_ptr) = NULL; \
|
|
} \
|
|
} while (0)
|
|
|
|
int FlowClearMemory(Flow *,uint8_t );
|
|
|
|
#endif /* __FLOW_H__ */
|
|
|