diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:39:49 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:39:49 +0000 |
commit | a0aa2307322cd47bbf416810ac0292925e03be87 (patch) | |
tree | 37076262a026c4b48c8a0e84f44ff9187556ca35 /src/detect.h | |
parent | Initial commit. (diff) | |
download | suricata-a0aa2307322cd47bbf416810ac0292925e03be87.tar.xz suricata-a0aa2307322cd47bbf416810ac0292925e03be87.zip |
Adding upstream version 1:7.0.3.upstream/1%7.0.3
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | src/detect.h | 1605 |
1 files changed, 1605 insertions, 0 deletions
diff --git a/src/detect.h b/src/detect.h new file mode 100644 index 0000000..0186545 --- /dev/null +++ b/src/detect.h @@ -0,0 +1,1605 @@ +/* Copyright (C) 2007-2023 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 __DETECT_H__ +#define __DETECT_H__ + +#include "suricata-common.h" +#include "flow.h" + +#include "detect-engine-proto.h" +#include "detect-reference.h" +#include "detect-metadata.h" +#include "detect-engine-register.h" + +#include "util-prefilter.h" +#include "util-mpm.h" +#include "util-spm.h" +#include "util-hash.h" +#include "util-hashlist.h" +#include "util-radix-tree.h" +#include "util-file.h" +#include "reputation.h" + +#define DETECT_MAX_RULE_SIZE 8192 + +#define DETECT_TRANSFORMS_MAX 16 + +/** default rule priority if not set through priority keyword or via + * classtype. */ +#define DETECT_DEFAULT_PRIO 3 + +/* forward declarations for the structures from detect-engine-sigorder.h */ +struct SCSigOrderFunc_; +struct SCSigSignatureWrapper_; + +/* Forward declarations for structures from Rust. */ +typedef struct SCDetectRequiresStatus SCDetectRequiresStatus; + +enum SignatureType { + SIG_TYPE_NOT_SET = 0, + SIG_TYPE_IPONLY, // rule is handled by IPONLY engine + SIG_TYPE_LIKE_IPONLY, // rule is handled by pkt engine, has action effect like ip-only + /** Proto detect only signature. + * Inspected once per direction when protocol detection is done. */ + SIG_TYPE_PDONLY, // rule is handled by PDONLY engine + SIG_TYPE_DEONLY, + SIG_TYPE_PKT, + SIG_TYPE_PKT_STREAM, + SIG_TYPE_STREAM, + + SIG_TYPE_APPLAYER, // app-layer but not tx, e.g. appproto + SIG_TYPE_APP_TX, // rule is handled by TX engine + + SIG_TYPE_MAX, +}; + +enum SignaturePropertyFlowAction { + SIG_PROP_FLOW_ACTION_PACKET, + SIG_PROP_FLOW_ACTION_FLOW, + SIG_PROP_FLOW_ACTION_FLOW_IF_STATEFUL, +}; + +struct SignatureProperties { + enum SignaturePropertyFlowAction flow_action; +}; + +extern const struct SignatureProperties signature_properties[SIG_TYPE_MAX]; + +/* + The detection engine groups similar signatures/rules together. Internally a + tree of different types of data is created on initialization. This is it's + global layout: + + For TCP/UDP + + - Flow direction + -- Protocol + -=- Dst port + + For the other protocols + + - Flow direction + -- Protocol +*/ + +/* holds the values for different possible lists in struct Signature. + * These codes are access points to particular lists in the array + * Signature->init_data->smlists[DETECT_SM_LIST_MAX]. */ +enum DetectSigmatchListEnum { + /* list for non-payload per packet matches, e.g. ttl, flow keyword */ + DETECT_SM_LIST_MATCH = 0, + /* list for payload and stream match */ + DETECT_SM_LIST_PMATCH, + + /* base64_data keyword uses some hardcoded logic so consider + * built-in + * TODO convert to inspect engine */ + DETECT_SM_LIST_BASE64_DATA, + + /* list for post match actions: flowbit set, flowint increment, etc */ + DETECT_SM_LIST_POSTMATCH, + + DETECT_SM_LIST_TMATCH, /**< post-detection tagging */ + + /* lists for alert thresholding and suppression */ + DETECT_SM_LIST_SUPPRESS, + DETECT_SM_LIST_THRESHOLD, + + DETECT_SM_LIST_MAX, + + /* start of dynamically registered lists */ + DETECT_SM_LIST_DYNAMIC_START = DETECT_SM_LIST_MAX, +}; + +/* used for Signature->list, which indicates which list + * we're adding keywords to in cases of sticky buffers like + * file_data */ +#define DETECT_SM_LIST_NOTSET INT_MAX + +/* + * DETECT ADDRESS + */ + +/* a is ... than b */ +enum { + ADDRESS_ER = -1, /**< error e.g. compare ipv4 and ipv6 */ + ADDRESS_LT, /**< smaller [aaa] [bbb] */ + ADDRESS_LE, /**< smaller with overlap [aa[bab]bb] */ + ADDRESS_EQ, /**< exactly equal [abababab] */ + ADDRESS_ES, /**< within [bb[aaa]bb] and [[abab]bbb] and [bbb[abab]] */ + ADDRESS_EB, /**< completely overlaps [aa[bbb]aa] and [[baba]aaa] and [aaa[baba]] */ + ADDRESS_GE, /**< bigger with overlap [bb[aba]aa] */ + ADDRESS_GT, /**< bigger [bbb] [aaa] */ +}; + +#define ADDRESS_FLAG_NOT 0x01 /**< address is negated */ + +/** \brief address structure for use in the detection engine. + * + * Contains the address information and matching information. + */ +typedef struct DetectAddress_ { + /** address data for this group */ + Address ip; + Address ip2; + + /** flags affecting this address */ + uint8_t flags; + + /** ptr to the previous address in the list */ + struct DetectAddress_ *prev; + /** ptr to the next address in the list */ + struct DetectAddress_ *next; +} DetectAddress; + +/** Address grouping head. IPv4 and IPv6 are split out */ +typedef struct DetectAddressHead_ { + DetectAddress *ipv4_head; + DetectAddress *ipv6_head; +} DetectAddressHead; + + +typedef struct DetectMatchAddressIPv4_ { + uint32_t ip; /**< address in host order, start of range */ + uint32_t ip2; /**< address in host order, end of range */ +} DetectMatchAddressIPv4; + +typedef struct DetectMatchAddressIPv6_ { + uint32_t ip[4]; + uint32_t ip2[4]; +} DetectMatchAddressIPv6; + +/* + * DETECT PORT + */ + +/* a is ... than b */ +enum { + PORT_ER = -1, /* error e.g. compare ipv4 and ipv6 */ + PORT_LT, /* smaller [aaa] [bbb] */ + PORT_LE, /* smaller with overlap [aa[bab]bb] */ + PORT_EQ, /* exactly equal [abababab] */ + PORT_ES, /* within [bb[aaa]bb] and [[abab]bbb] and [bbb[abab]] */ + PORT_EB, /* completely overlaps [aa[bbb]aa] and [[baba]aaa] and [aaa[baba]] */ + PORT_GE, /* bigger with overlap [bb[aba]aa] */ + PORT_GT, /* bigger [bbb] [aaa] */ +}; + +#define PORT_FLAG_ANY 0x01 /**< 'any' special port */ +#define PORT_FLAG_NOT 0x02 /**< negated port */ +#define PORT_SIGGROUPHEAD_COPY 0x04 /**< sgh is a ptr copy */ + +/** \brief Port structure for detection engine */ +typedef struct DetectPort_ { + uint16_t port; + uint16_t port2; + + uint8_t flags; /**< flags for this port */ + + /* signatures that belong in this group + * + * If the PORT_SIGGROUPHEAD_COPY flag is set, we don't own this pointer + * (memory is freed elsewhere). + */ + struct SigGroupHead_ *sh; + + struct DetectPort_ *prev; + struct DetectPort_ *next; +} DetectPort; + +/* Signature flags */ +/** \note: additions should be added to the rule analyzer as well */ + +#define SIG_FLAG_SRC_ANY BIT_U32(0) /**< source is any */ +#define SIG_FLAG_DST_ANY BIT_U32(1) /**< destination is any */ +#define SIG_FLAG_SP_ANY BIT_U32(2) /**< source port is any */ +#define SIG_FLAG_DP_ANY BIT_U32(3) /**< destination port is any */ + +#define SIG_FLAG_NOALERT BIT_U32(4) /**< no alert flag is set */ +#define SIG_FLAG_DSIZE BIT_U32(5) /**< signature has a dsize setting */ +#define SIG_FLAG_APPLAYER BIT_U32(6) /**< signature applies to app layer instead of packets */ + +// vacancy + +#define SIG_FLAG_REQUIRE_PACKET BIT_U32(9) /**< signature is requiring packet match */ +#define SIG_FLAG_REQUIRE_STREAM BIT_U32(10) /**< signature is requiring stream match */ + +#define SIG_FLAG_MPM_NEG BIT_U32(11) + +#define SIG_FLAG_FLUSH BIT_U32(12) /**< detection logic needs stream flush notification */ + +// vacancies + +#define SIG_FLAG_REQUIRE_FLOWVAR BIT_U32(17) /**< signature can only match if a flowbit, flowvar or flowint is available. */ + +#define SIG_FLAG_FILESTORE BIT_U32(18) /**< signature has filestore keyword */ + +#define SIG_FLAG_TOSERVER BIT_U32(19) +#define SIG_FLAG_TOCLIENT BIT_U32(20) + +#define SIG_FLAG_TLSSTORE BIT_U32(21) + +#define SIG_FLAG_BYPASS BIT_U32(22) + +#define SIG_FLAG_PREFILTER BIT_U32(23) /**< sig is part of a prefilter engine */ + +// vacancy + +/** Info for Source and Target identification */ +#define SIG_FLAG_SRC_IS_TARGET BIT_U32(25) +/** Info for Source and Target identification */ +#define SIG_FLAG_DEST_IS_TARGET BIT_U32(26) + +#define SIG_FLAG_HAS_TARGET (SIG_FLAG_DEST_IS_TARGET|SIG_FLAG_SRC_IS_TARGET) + +/* signature init flags */ +// available 0 +#define SIG_FLAG_INIT_PACKET BIT_U32(1) /**< signature has matches against a packet (as opposed to app layer) */ +#define SIG_FLAG_INIT_FLOW BIT_U32(2) /**< signature has a flow setting */ +#define SIG_FLAG_INIT_BIDIREC BIT_U32(3) /**< signature has bidirectional operator */ +#define SIG_FLAG_INIT_FIRST_IPPROTO_SEEN \ + BIT_U32(4) /** < signature has seen the first ip_proto keyword */ +#define SIG_FLAG_INIT_STATE_MATCH BIT_U32(6) /**< signature has matches that require stateful inspection */ +#define SIG_FLAG_INIT_NEED_FLUSH BIT_U32(7) +#define SIG_FLAG_INIT_PRIO_EXPLICIT \ + BIT_U32(8) /**< priority is explicitly set by the priority keyword */ +#define SIG_FLAG_INIT_FILEDATA BIT_U32(9) /**< signature has filedata keyword */ +#define SIG_FLAG_INIT_JA3 BIT_U32(10) /**< signature has ja3 keyword */ +#define SIG_FLAG_INIT_OVERFLOW BIT_U32(11) /**< signature has overflown buffers */ + +/* signature mask flags */ +/** \note: additions should be added to the rule analyzer as well */ +#define SIG_MASK_REQUIRE_PAYLOAD BIT_U8(0) +#define SIG_MASK_REQUIRE_FLOW BIT_U8(1) +#define SIG_MASK_REQUIRE_FLAGS_INITDEINIT BIT_U8(2) /* SYN, FIN, RST */ +#define SIG_MASK_REQUIRE_FLAGS_UNUSUAL BIT_U8(3) /* URG, ECN, CWR */ +#define SIG_MASK_REQUIRE_NO_PAYLOAD BIT_U8(4) +#define SIG_MASK_REQUIRE_DCERPC BIT_U8(5) /* require either SMB+DCE or raw DCE */ +// vacancy +#define SIG_MASK_REQUIRE_ENGINE_EVENT BIT_U8(7) + +/* for now a uint8_t is enough */ +#define SignatureMask uint8_t + +#define DETECT_ENGINE_THREAD_CTX_FRAME_ID_SET 0x0001 +#define DETECT_ENGINE_THREAD_CTX_STREAM_CONTENT_MATCH 0x0004 + +#define FILE_SIG_NEED_FILE 0x01 +#define FILE_SIG_NEED_FILENAME 0x02 +#define FILE_SIG_NEED_MAGIC 0x04 /**< need the start of the file */ +#define FILE_SIG_NEED_FILECONTENT 0x08 +#define FILE_SIG_NEED_MD5 0x10 +#define FILE_SIG_NEED_SHA1 0x20 +#define FILE_SIG_NEED_SHA256 0x40 +#define FILE_SIG_NEED_SIZE 0x80 + +/* Detection Engine flags */ +#define DE_QUIET 0x01 /**< DE is quiet (esp for unittests) */ + +typedef struct IPOnlyCIDRItem_ { + /* address data for this item */ + uint8_t family; + /* netmask in CIDR values (ex. /16 /18 /24..) */ + uint8_t netmask; + /* If this host or net is negated for the signum */ + uint8_t negated; + + uint32_t ip[4]; + SigIntId signum; /**< our internal id */ + + /* linked list, the header should be the biggest network */ + struct IPOnlyCIDRItem_ *next; + +} IPOnlyCIDRItem; + +/** \brief Used to start a pointer to SigMatch context + * Should never be dereferenced without casting to something else. + */ +typedef struct SigMatchCtx_ { + int foo; +} SigMatchCtx; + +/** \brief a single match condition for a signature */ +typedef struct SigMatch_ { + uint16_t type; /**< match type */ + uint16_t idx; /**< position in the signature */ + SigMatchCtx *ctx; /**< plugin specific data */ + struct SigMatch_ *next; + struct SigMatch_ *prev; +} SigMatch; + +/** \brief Data needed for Match() */ +typedef struct SigMatchData_ { + uint16_t type; /**< match type */ + uint8_t is_last; /**< Last element of the list */ + SigMatchCtx *ctx; /**< plugin specific data */ +} SigMatchData; + +struct DetectEngineThreadCtx_;// DetectEngineThreadCtx; + +/* inspection buffer is a simple structure that is passed between prefilter, + * transformation functions and inspection functions. + * Initially setup with 'orig' ptr and len, transformations can then take + * then and fill the 'buf'. Multiple transformations can update the buffer, + * both growing and shrinking it. + * Prefilter and inspection will only deal with 'inspect'. */ + +typedef struct InspectionBuffer { + const uint8_t *inspect; /**< active pointer, points either to ::buf or ::orig */ + uint64_t inspect_offset; + uint32_t inspect_len; /**< size of active data. See to ::len or ::orig_len */ + bool initialized; /**< is initialized. ::inspect might be NULL if transform lead to 0 size */ + uint8_t flags; /**< DETECT_CI_FLAGS_* for use with DetectEngineContentInspection */ +#ifdef DEBUG_VALIDATION + bool multi; +#endif + uint32_t len; /**< how much is in use */ + uint8_t *buf; + uint32_t size; /**< size of the memory allocation */ + + uint32_t orig_len; + const uint8_t *orig; +} InspectionBuffer; + +/* inspection buffers are kept per tx (in det_ctx), but some protocols + * need a bit more. A single TX might have multiple buffers, e.g. files in + * SMTP or DNS queries. Since all prefilters+transforms run before the + * individual rules need the same buffers, we need a place to store the + * transformed data. This array of arrays is that place. */ + +typedef struct InspectionBufferMultipleForList { + InspectionBuffer *inspection_buffers; + uint32_t size; /**< size in number of elements */ + uint32_t max:31; /**< max id in use in this run */ + uint32_t init:1; /**< first time used this run. Used for clean logic */ +} InspectionBufferMultipleForList; + +typedef struct TransformData_ { + int transform; + void *options; +} TransformData; + +typedef struct DetectEngineTransforms { + TransformData transforms[DETECT_TRANSFORMS_MAX]; + int cnt; +} DetectEngineTransforms; + +/** callback for getting the buffer we need to prefilter/inspect */ +typedef InspectionBuffer *(*InspectionBufferGetDataPtr)( + struct DetectEngineThreadCtx_ *det_ctx, + const DetectEngineTransforms *transforms, + Flow *f, const uint8_t flow_flags, + void *txv, const int list_id); +struct DetectEngineAppInspectionEngine_; + +typedef uint8_t (*InspectEngineFuncPtr2)(struct DetectEngineCtx_ *de_ctx, + struct DetectEngineThreadCtx_ *det_ctx, + const struct DetectEngineAppInspectionEngine_ *engine, const struct Signature_ *s, Flow *f, + uint8_t flags, void *alstate, void *txv, uint64_t tx_id); + +typedef struct DetectEngineAppInspectionEngine_ { + AppProto alproto; + uint8_t dir; + uint8_t id; /**< per sig id used in state keeping */ + bool mpm; + bool stream; + uint16_t sm_list; + uint16_t sm_list_base; /**< base buffer being transformed */ + int16_t progress; + + struct { + InspectionBufferGetDataPtr GetData; + InspectEngineFuncPtr2 Callback; + /** pointer to the transforms in the 'DetectBuffer entry for this list */ + const DetectEngineTransforms *transforms; + } v2; + + SigMatchData *smd; + + struct DetectEngineAppInspectionEngine_ *next; +} DetectEngineAppInspectionEngine; + +typedef struct DetectBufferType_ { + char name[32]; + char description[128]; + int id; + int parent_id; + bool mpm; + bool packet; /**< compat to packet matches */ + bool frame; /**< is about Frame inspection */ + bool supports_transforms; + bool multi_instance; /**< buffer supports multiple buffer instances per tx */ + void (*SetupCallback)(const struct DetectEngineCtx_ *, struct Signature_ *); + bool (*ValidateCallback)(const struct Signature_ *, const char **sigerror); + DetectEngineTransforms transforms; +} DetectBufferType; + +struct DetectEnginePktInspectionEngine; + +/** + * \param alert_flags[out] for setting PACKET_ALERT_FLAG_* + */ +typedef int (*InspectionBufferPktInspectFunc)( + struct DetectEngineThreadCtx_ *, + const struct DetectEnginePktInspectionEngine *engine, + const struct Signature_ *s, + Packet *p, uint8_t *alert_flags); + +/** callback for getting the buffer we need to prefilter/inspect */ +typedef InspectionBuffer *(*InspectionBufferGetPktDataPtr)( + struct DetectEngineThreadCtx_ *det_ctx, + const DetectEngineTransforms *transforms, + Packet *p, const int list_id); + +typedef struct DetectEnginePktInspectionEngine { + SigMatchData *smd; + bool mpm; + uint16_t sm_list; + uint16_t sm_list_base; + struct { + InspectionBufferGetPktDataPtr GetData; + InspectionBufferPktInspectFunc Callback; + /** pointer to the transforms in the 'DetectBuffer entry for this list */ + const DetectEngineTransforms *transforms; + } v1; + struct DetectEnginePktInspectionEngine *next; +} DetectEnginePktInspectionEngine; + +struct Frame; +struct Frames; +struct DetectEngineFrameInspectionEngine; + +/** + * \param alert_flags[out] for setting PACKET_ALERT_FLAG_* + */ +typedef int (*InspectionBufferFrameInspectFunc)(struct DetectEngineThreadCtx_ *, + const struct DetectEngineFrameInspectionEngine *engine, const struct Signature_ *s, + Packet *p, const struct Frames *frames, const struct Frame *frame); + +typedef struct DetectEngineFrameInspectionEngine { + AppProto alproto; + uint8_t dir; + uint8_t type; + bool mpm; + uint16_t sm_list; + uint16_t sm_list_base; + struct { + InspectionBufferFrameInspectFunc Callback; + /** pointer to the transforms in the 'DetectBuffer entry for this list */ + const DetectEngineTransforms *transforms; + } v1; + SigMatchData *smd; + struct DetectEngineFrameInspectionEngine *next; +} DetectEngineFrameInspectionEngine; + +typedef struct SignatureInitDataBuffer_ { + uint32_t id; /**< buffer id */ + bool sm_init; /**< initialized by sigmatch, which is likely something like `urilen:10; http.uri; + content:"abc";`. These need to be in the same list. Unset once `http.uri` is + set up. */ + bool multi_capable; /**< true if we can have multiple instances of this buffer, so e.g. for + http.uri. */ + /* sig match list */ + SigMatch *head; + SigMatch *tail; +} SignatureInitDataBuffer; + +typedef struct SignatureInitData_ { + /** Number of sigmatches. Used for assigning SigMatch::idx */ + uint16_t sm_cnt; + + /** option was prefixed with '!'. Only set for sigmatches that + * have the SIGMATCH_HANDLE_NEGATION flag set. */ + bool negated; + + /* track if we saw any negation in the addresses. If so, we + * skip it for ip-only */ + bool src_contains_negation; + bool dst_contains_negation; + + /* used to hold flags that are used during init */ + uint32_t init_flags; + /* coccinelle: SignatureInitData:init_flags:SIG_FLAG_INIT_ */ + + /* used at init to determine max dsize */ + SigMatch *dsize_sm; + + /* list id for `mpm_sm`. Should always match `SigMatchListSMBelongsTo(s, mpm_sm)`. */ + int mpm_sm_list; + /* the fast pattern added from this signature */ + SigMatch *mpm_sm; + /* used to speed up init of prefilter */ + SigMatch *prefilter_sm; + + /* SigMatch list used for adding content and friends. E.g. file_data; */ + int list; + bool list_set; + + DetectEngineTransforms transforms; + + /** score to influence rule grouping. A higher value leads to a higher + * likelihood of a rulegroup with this sig ending up as a contained + * group. */ + int whitelist; + + /** address settings for this signature */ + const DetectAddressHead *src, *dst; + + int prefilter_list; + + /* holds built-in sm lists */ + struct SigMatch_ *smlists[DETECT_SM_LIST_MAX]; + /* holds built-in sm lists' tails */ + struct SigMatch_ *smlists_tail[DETECT_SM_LIST_MAX]; + + /* Storage for buffers. */ + SignatureInitDataBuffer *buffers; + uint32_t buffer_index; + uint32_t buffers_size; + SignatureInitDataBuffer *curbuf; + + /* highest list/buffer id which holds a DETECT_CONTENT */ + uint32_t max_content_list_id; +} SignatureInitData; + +/** \brief Signature container */ +typedef struct Signature_ { + uint32_t flags; + /* coccinelle: Signature:flags:SIG_FLAG_ */ + enum SignatureType type; + + AppProto alproto; + + uint16_t dsize_low; + uint16_t dsize_high; + uint8_t dsize_mode; + + SignatureMask mask; + SigIntId num; /**< signature number, internal id */ + + /** inline -- action */ + uint8_t action; + uint8_t file_flags; + + /** addresses, ports and proto this sig matches on */ + DetectProto proto; + + /** classification id **/ + uint16_t class_id; + + /** ipv4 match arrays */ + uint16_t addr_dst_match4_cnt; + uint16_t addr_src_match4_cnt; + uint16_t addr_dst_match6_cnt; + uint16_t addr_src_match6_cnt; + DetectMatchAddressIPv4 *addr_dst_match4; + DetectMatchAddressIPv4 *addr_src_match4; + /** ipv6 match arrays */ + DetectMatchAddressIPv6 *addr_dst_match6; + DetectMatchAddressIPv6 *addr_src_match6; + + uint32_t id; /**< sid, set by the 'sid' rule keyword */ + uint32_t gid; /**< generator id */ + uint32_t rev; + int prio; + + /** port settings for this signature */ + DetectPort *sp, *dp; + +#ifdef PROFILE_RULES + uint16_t profiling_id; +#endif + + /** netblocks and hosts specified at the sid, in CIDR format */ + IPOnlyCIDRItem *cidr_src, *cidr_dst; + + DetectEngineAppInspectionEngine *app_inspect; + DetectEnginePktInspectionEngine *pkt_inspect; + DetectEngineFrameInspectionEngine *frame_inspect; + + /* Matching structures for the built-ins. The others are in + * their inspect engines. */ + SigMatchData *sm_arrays[DETECT_SM_LIST_MAX]; + + /* memory is still owned by the sm_lists/sm_arrays entry */ + const struct DetectFilestoreData_ *filestore_ctx; + + char *msg; + + /** classification message */ + char *class_msg; + /** Reference */ + DetectReference *references; + /** Metadata */ + DetectMetadataHead *metadata; + + char *sig_str; + + SignatureInitData *init_data; + + /** ptr to the next sig in the list */ + struct Signature_ *next; +} Signature; + +enum DetectBufferMpmType { + DETECT_BUFFER_MPM_TYPE_PKT, + DETECT_BUFFER_MPM_TYPE_APP, + DETECT_BUFFER_MPM_TYPE_FRAME, + /* must be last */ + DETECT_BUFFER_MPM_TYPE_SIZE, +}; + +/** \brief one time registration of keywords at start up */ +typedef struct DetectBufferMpmRegistry_ { + const char *name; + char pname[32]; /**< name used in profiling */ + int direction; /**< SIG_FLAG_TOSERVER or SIG_FLAG_TOCLIENT */ + int16_t sm_list; + int16_t sm_list_base; + int priority; + int id; /**< index into this array and result arrays */ + enum DetectBufferMpmType type; + int sgh_mpm_context; + + int (*PrefilterRegisterWithListId)(struct DetectEngineCtx_ *de_ctx, struct SigGroupHead_ *sgh, + MpmCtx *mpm_ctx, const struct DetectBufferMpmRegistry_ *mpm_reg, int list_id); + DetectEngineTransforms transforms; + + union { + /* app-layer matching: use if type == DETECT_BUFFER_MPM_TYPE_APP */ + struct { + InspectionBufferGetDataPtr GetData; + AppProto alproto; + int tx_min_progress; + } app_v2; + + /* pkt matching: use if type == DETECT_BUFFER_MPM_TYPE_PKT */ + struct { + int (*PrefilterRegisterWithListId)(struct DetectEngineCtx_ *de_ctx, + struct SigGroupHead_ *sgh, MpmCtx *mpm_ctx, + const struct DetectBufferMpmRegistry_ *mpm_reg, int list_id); + InspectionBufferGetPktDataPtr GetData; + } pkt_v1; + + /* frame matching: use if type == DETECT_BUFFER_MPM_TYPE_FRAME */ + struct { + AppProto alproto; + uint8_t type; + } frame_v1; + }; + + struct DetectBufferMpmRegistry_ *next; +} DetectBufferMpmRegistry; + +/* helper structure to track pattern stats and assign pattern id's. */ +typedef struct DetectPatternTracker { + const struct DetectContentData_ *cd; + int sm_list; + uint32_t cnt; + uint32_t mpm; +} DetectPatternTracker; + +typedef struct DetectReplaceList_ { + struct DetectContentData_ *cd; + uint8_t *found; + struct DetectReplaceList_ *next; +} DetectReplaceList; + +/** only execute flowvar storage if rule matched */ +#define DETECT_VAR_TYPE_FLOW_POSTMATCH 1 +#define DETECT_VAR_TYPE_PKT_POSTMATCH 2 + +/** list for flowvar store candidates, to be stored from + * post-match function */ +typedef struct DetectVarList_ { + uint32_t idx; /**< flowvar name idx */ + uint16_t len; /**< data len */ + uint16_t key_len; + int type; /**< type of store candidate POSTMATCH or ALWAYS */ + uint8_t *key; + uint8_t *buffer; /**< alloc'd buffer, may be freed by + post-match, post-non-match */ + struct DetectVarList_ *next; +} DetectVarList; + +typedef struct SCFPSupportSMList_ { + int list_id; + int priority; + struct SCFPSupportSMList_ *next; +} SCFPSupportSMList; + +/** \brief IP only rules matching ctx. */ +typedef struct DetectEngineIPOnlyCtx_ { + /* Lookup trees */ + SCRadixTree *tree_ipv4src, *tree_ipv4dst; + SCRadixTree *tree_ipv6src, *tree_ipv6dst; + + /* Used to build the radix trees */ + IPOnlyCIDRItem *ip_src, *ip_dst; + uint32_t max_idx; + + /* Used to map large signums to smaller values to compact the bitsets + * stored in the radix trees */ + uint32_t *sig_mapping; + uint32_t sig_mapping_size; +} DetectEngineIPOnlyCtx; + +typedef struct DetectEngineLookupFlow_ { + DetectPort *tcp; + DetectPort *udp; + struct SigGroupHead_ *sgh[256]; +} DetectEngineLookupFlow; + +#include "detect-threshold.h" + +/** \brief threshold ctx */ +typedef struct ThresholdCtx_ { + SCMutex threshold_table_lock; /**< Mutex for hash table */ + + /** to support rate_filter "by_rule" option */ + DetectThresholdEntry **th_entry; + uint32_t th_size; +} ThresholdCtx; + +typedef struct SigString_ { + char *filename; + char *sig_str; + char *sig_error; + int line; + TAILQ_ENTRY(SigString_) next; +} SigString; + +/** \brief Signature loader statistics */ +typedef struct SigFileLoaderStat_ { + TAILQ_HEAD(, SigString_) failed_sigs; + int bad_files; + int total_files; + int good_sigs_total; + int bad_sigs_total; + int skipped_sigs_total; +} SigFileLoaderStat; + +typedef struct DetectEngineThreadKeywordCtxItem_ { + void *(*InitFunc)(void *); + void (*FreeFunc)(void *); + void *data; + struct DetectEngineThreadKeywordCtxItem_ *next; + int id; + const char *name; /* keyword name, for error printing */ +} DetectEngineThreadKeywordCtxItem; + +enum DetectEnginePrefilterSetting +{ + DETECT_PREFILTER_MPM = 0, /**< use only mpm / fast_pattern */ + DETECT_PREFILTER_AUTO = 1, /**< use mpm + keyword prefilters */ +}; + +enum DetectEngineType +{ + DETECT_ENGINE_TYPE_NORMAL = 0, + DETECT_ENGINE_TYPE_DD_STUB = 1, /* delayed detect stub: can be reloaded */ + DETECT_ENGINE_TYPE_MT_STUB = 2, /* multi-tenant stub: cannot be reloaded */ + DETECT_ENGINE_TYPE_TENANT = 3, +}; + +/* Flow states: + * toserver + * toclient + */ +#define FLOW_STATES 2 + +/** \brief main detection engine ctx */ +typedef struct DetectEngineCtx_ { + bool failure_fatal; + uint8_t flags; /**< only DE_QUIET */ + uint8_t mpm_matcher; /**< mpm matcher this ctx uses */ + uint8_t spm_matcher; /**< spm matcher this ctx uses */ + + uint32_t tenant_id; + + Signature *sig_list; + uint32_t sig_cnt; + + /* version of the srep data */ + uint32_t srep_version; + + /* reputation for netblocks */ + SRepCIDRTree *srepCIDR_ctx; + + Signature **sig_array; + uint32_t sig_array_size; /* size in bytes */ + uint32_t sig_array_len; /* size in array members */ + + uint32_t signum; + + /** Maximum value of all our sgh's non_mpm_store_cnt setting, + * used to alloc det_ctx::non_mpm_id_array */ + uint32_t non_pf_store_cnt_max; + + /* used by the signature ordering module */ + struct SCSigOrderFunc_ *sc_sig_order_funcs; + + /* main sigs */ + DetectEngineLookupFlow flow_gh[FLOW_STATES]; + + /* init phase vars */ + HashListTable *sgh_hash_table; + + HashListTable *mpm_hash_table; + HashListTable *pattern_hash_table; + + /* hash table used to cull out duplicate sigs */ + HashListTable *dup_sig_hash_table; + + DetectEngineIPOnlyCtx io_ctx; + ThresholdCtx ths_ctx; + + /* maximum recursion depth for content inspection */ + int inspection_recursion_limit; + + /* registration id for per thread ctx for the filemagic/file.magic keywords */ + int filemagic_thread_ctx_id; + + /* spm thread context prototype, built as spm matchers are constructed and + * later used to construct thread context for each thread. */ + SpmGlobalThreadCtx *spm_global_thread_ctx; + + /* Config options */ + + uint16_t max_uniq_toclient_groups; + uint16_t max_uniq_toserver_groups; + + /* max flowbit id that is used */ + uint32_t max_fb_id; + + MpmCtxFactoryContainer *mpm_ctx_factory_container; + + /* array containing all sgh's in use so we can loop + * through it in Stage4. */ + struct SigGroupHead_ **sgh_array; + uint32_t sgh_array_cnt; + uint32_t sgh_array_size; + + int32_t sgh_mpm_context_proto_tcp_packet; + int32_t sgh_mpm_context_proto_udp_packet; + int32_t sgh_mpm_context_proto_other_packet; + int32_t sgh_mpm_context_stream; + + /* the max local id used amongst all sigs */ + int32_t byte_extract_max_local_id; + + /** version of the detect engine. The version is incremented on reloads */ + uint32_t version; + + /** sgh for signatures that match against invalid packets. In those cases + * we can't lookup by proto, address, port as we don't have these */ + struct SigGroupHead_ *decoder_event_sgh; + + /* Maximum size of the buffer for decoded base64 data. */ + uint32_t base64_decode_max_len; + + /** Store rule file and line so that parsers can use them in errors. */ + int rule_line; + char *rule_file; + const char *sigerror; + bool sigerror_silent; + bool sigerror_ok; + + /** The rule errored out due to missing requirements. */ + bool sigerror_requires; + + bool filedata_config_initialized; + + /* specify the configuration for mpm context factory */ + uint8_t sgh_mpm_ctx_cnf; + + int keyword_id; + /** hash list of keywords that need thread local ctxs */ + HashListTable *keyword_hash; + + struct { + uint32_t content_limit; + uint32_t content_inspect_min_size; + uint32_t content_inspect_window; + } filedata_config[ALPROTO_MAX]; + +#ifdef PROFILE_RULES + struct SCProfileDetectCtx_ *profile_ctx; +#endif +#ifdef PROFILING + struct SCProfileKeywordDetectCtx_ *profile_keyword_ctx; + struct SCProfilePrefilterDetectCtx_ *profile_prefilter_ctx; + struct SCProfileKeywordDetectCtx_ **profile_keyword_ctx_per_list; + struct SCProfileSghDetectCtx_ *profile_sgh_ctx; + uint32_t profile_match_logging_threshold; +#endif + char config_prefix[64]; + + enum DetectEngineType type; + + /** how many de_ctx' are referencing this */ + uint32_t ref_cnt; + /** list in master: either active or freelist */ + struct DetectEngineCtx_ *next; + + /** id of loader thread 'owning' this de_ctx */ + int loader_id; + + /** are we using just mpm or also other prefilters */ + enum DetectEnginePrefilterSetting prefilter_setting; + + HashListTable *dport_hash_table; + + DetectPort *tcp_whitelist; + DetectPort *udp_whitelist; + + /** table for storing the string representation with the parsers result */ + HashListTable *address_table; + + /** table to store metadata keys and values */ + HashTable *metadata_table; + + /* hash tables with rule-time buffer registration. Start time registration + * is in detect-engine.c::g_buffer_type_hash */ + HashListTable *buffer_type_hash_name; + HashListTable *buffer_type_hash_id; + uint32_t buffer_type_id; + + uint32_t app_mpms_list_cnt; + DetectBufferMpmRegistry *app_mpms_list; + /* list with app inspect engines. Both the start-time registered ones and + * the rule-time registered ones. */ + DetectEngineAppInspectionEngine *app_inspect_engines; + DetectEnginePktInspectionEngine *pkt_inspect_engines; + DetectBufferMpmRegistry *pkt_mpms_list; + uint32_t pkt_mpms_list_cnt; + DetectEngineFrameInspectionEngine *frame_inspect_engines; + DetectBufferMpmRegistry *frame_mpms_list; + uint32_t frame_mpms_list_cnt; + + uint32_t prefilter_id; + HashListTable *prefilter_hash_table; + + /** time of last ruleset reload */ + struct timeval last_reload; + + /** signatures stats */ + SigFileLoaderStat sig_stat; + + /* list of Fast Pattern registrations. Initially filled using a copy of + * `g_fp_support_smlist_list`, then extended at rule loading time if needed */ + SCFPSupportSMList *fp_support_smlist_list; + + /** per keyword flag indicating if a prefilter has been + * set for it. If true, the setup function will have to + * run. */ + bool sm_types_prefilter[DETECT_TBLSIZE]; + bool sm_types_silent_error[DETECT_TBLSIZE]; + + /* classification config parsing */ + + /* hash table used for holding the classification config info */ + HashTable *class_conf_ht; + pcre2_code *class_conf_regex; + pcre2_match_data *class_conf_regex_match; + + /* reference config parsing */ + + /* hash table used for holding the reference config info */ + HashTable *reference_conf_ht; + pcre2_code *reference_conf_regex; + pcre2_match_data *reference_conf_regex_match; + + /* --engine-analysis */ + struct EngineAnalysisCtx_ *ea; + + /* path to the tenant yaml for this engine */ + char *tenant_path; + + /* Track rule requirements for reporting after loading rules. */ + SCDetectRequiresStatus *requirements; +} DetectEngineCtx; + +/* Engine groups profiles (low, medium, high, custom) */ +enum { + ENGINE_PROFILE_UNKNOWN, + ENGINE_PROFILE_LOW, + ENGINE_PROFILE_MEDIUM, + ENGINE_PROFILE_HIGH, + ENGINE_PROFILE_CUSTOM, +}; + +/* Siggroup mpm context profile */ +enum { + ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL = 0, + ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE, + ENGINE_SGH_MPM_FACTORY_CONTEXT_AUTO, +#define ENGINE_SGH_MPM_FACTORY_CONTEXT_START_ID_RANGE (ENGINE_SGH_MPM_FACTORY_CONTEXT_AUTO + 1) +}; + +#define DETECT_FILESTORE_MAX 15 + +typedef struct SignatureNonPrefilterStore_ { + SigIntId id; + SignatureMask mask; + AppProto alproto; +} SignatureNonPrefilterStore; + +/** array of TX inspect rule candidates */ +typedef struct RuleMatchCandidateTx { + SigIntId id; /**< internal signature id */ + uint32_t *flags; /**< inspect flags ptr */ + union { + struct { + bool stream_stored; + uint8_t stream_result; + }; + uint32_t stream_reset; + }; + + const Signature *s; /**< ptr to sig */ +} RuleMatchCandidateTx; + +/** + * Detection engine thread data. + */ +typedef struct DetectEngineThreadCtx_ { + /** \note multi-tenant hash lookup code from Detect() *depends* + * on this being the first member */ + uint32_t tenant_id; + + /* the thread to which this detection engine thread belongs */ + ThreadVars *tv; + + /** Array of non-prefiltered sigs that need to be evaluated. Updated + * per packet based on the rule group and traffic properties. */ + SigIntId *non_pf_id_array; + uint32_t non_pf_id_cnt; // size is cnt * sizeof(uint32_t) + + uint32_t mt_det_ctxs_cnt; + struct DetectEngineThreadCtx_ **mt_det_ctxs; + HashTable *mt_det_ctxs_hash; + + struct DetectEngineTenantMapping_ *tenant_array; + uint32_t tenant_array_size; + + uint32_t (*TenantGetId)(const void *, const Packet *p); + + /* detection engine variables */ + + uint64_t raw_stream_progress; + + /** offset into the payload of the last match by: + * content, pcre, etc */ + uint32_t buffer_offset; + /* used by pcre match function alone */ + uint32_t pcre_match_start_offset; + + /* counter for the filestore array below -- up here for cache reasons. */ + uint16_t filestore_cnt; + + /** id for alert counter */ + uint16_t counter_alerts; + /** id for discarded alerts counter */ + uint16_t counter_alerts_overflow; + /** id for suppressed alerts counter */ + uint16_t counter_alerts_suppressed; +#ifdef PROFILING + uint16_t counter_mpm_list; + uint16_t counter_nonmpm_list; + uint16_t counter_fnonmpm_list; + uint16_t counter_match_list; +#endif + + struct { + InspectionBuffer *buffers; + uint32_t buffers_size; /**< in number of elements */ + uint32_t to_clear_idx; + uint32_t *to_clear_queue; + } inspect; + + struct { + /** inspection buffers for more complex case. As we can inspect multiple + * buffers in parallel, we need this extra wrapper struct */ + InspectionBufferMultipleForList *buffers; + uint32_t buffers_size; /**< in number of elements */ + uint32_t to_clear_idx; + uint32_t *to_clear_queue; + } multi_inspect; + + /* used to discontinue any more matching */ + uint16_t discontinue_matching; + uint16_t flags; /**< DETECT_ENGINE_THREAD_CTX_* flags */ + + /* true if tx_id is set */ + bool tx_id_set; + /** ID of the transaction currently being inspected. */ + uint64_t tx_id; + int64_t frame_id; + uint64_t frame_inspect_progress; /**< used to set Frame::inspect_progress after all inspection + on a frame is complete. */ + Packet *p; + + uint16_t alert_queue_size; + uint16_t alert_queue_capacity; + PacketAlert *alert_queue; + + SC_ATOMIC_DECLARE(int, so_far_used_by_detect); + + /* holds the current recursion depth on content inspection */ + int inspection_recursion_counter; + + /** array of signature pointers we're going to inspect in the detection + * loop. */ + Signature **match_array; + /** size of the array in items (mem size if * sizeof(Signature *) + * Only used during initialization. */ + uint32_t match_array_len; + /** size in use */ + SigIntId match_array_cnt; + + RuleMatchCandidateTx *tx_candidates; + uint32_t tx_candidates_size; + + SignatureNonPrefilterStore *non_pf_store_ptr; + uint32_t non_pf_store_cnt; + + /** pointer to the current mpm ctx that is stored + * in a rule group head -- can be either a content + * or uricontent ctx. */ + MpmThreadCtx mtc; /**< thread ctx for the mpm */ + MpmThreadCtx mtcu; /**< thread ctx for uricontent mpm */ + MpmThreadCtx mtcs; /**< thread ctx for stream mpm */ + PrefilterRuleStore pmq; + + /** SPM thread context used for scanning. This has been cloned from the + * prototype held by DetectEngineCtx. */ + SpmThreadCtx *spm_thread_ctx; + + /* byte_* values */ + uint64_t *byte_values; + + /* string to replace */ + DetectReplaceList *replist; + /* vars to store in post match function */ + DetectVarList *varlist; + + /* Array in which the filestore keyword stores file id and tx id. If the + * full signature matches, these are processed by a post-match filestore + * function to finalize the store. */ + struct { + uint32_t file_id; + uint64_t tx_id; + } filestore[DETECT_FILESTORE_MAX]; + + DetectEngineCtx *de_ctx; + /** store for keyword contexts that need a per thread storage. Per de_ctx. */ + void **keyword_ctxs_array; + int keyword_ctxs_size; + /** store for keyword contexts that need a per thread storage. Global. */ + int global_keyword_ctxs_size; + void **global_keyword_ctxs_array; + + uint8_t *base64_decoded; + int base64_decoded_len; + int base64_decoded_len_max; + + AppLayerDecoderEvents *decoder_events; + uint16_t events; + +#ifdef DEBUG + uint64_t pkt_stream_add_cnt; + uint64_t payload_mpm_cnt; + uint64_t payload_mpm_size; + uint64_t stream_mpm_cnt; + uint64_t stream_mpm_size; + uint64_t payload_persig_cnt; + uint64_t payload_persig_size; + uint64_t stream_persig_cnt; + uint64_t stream_persig_size; +#endif +#ifdef PROFILE_RULES + struct SCProfileData_ *rule_perf_data; + int rule_perf_data_size; + uint32_t rule_perf_last_sync; +#endif +#ifdef PROFILING + struct SCProfileKeywordData_ *keyword_perf_data; + struct SCProfileKeywordData_ **keyword_perf_data_per_list; + int keyword_perf_list; /**< list we're currently inspecting, DETECT_SM_LIST_* */ + struct SCProfileSghData_ *sgh_perf_data; + + struct SCProfilePrefilterData_ *prefilter_perf_data; + /** bytes inspected by current prefilter callback call */ + uint64_t prefilter_bytes; + /** number of times we inspected a buffer */ + uint64_t prefilter_bytes_called; +#endif +} DetectEngineThreadCtx; + +/** \brief element in sigmatch type table. + */ +typedef struct SigTableElmt_ { + /** Packet match function pointer */ + int (*Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); + + /** AppLayer TX match function pointer */ + int (*AppLayerTxMatch)(DetectEngineThreadCtx *, Flow *, + uint8_t flags, void *alstate, void *txv, + const Signature *, const SigMatchCtx *); + + /** File match function pointer */ + int (*FileMatch)(DetectEngineThreadCtx *, + Flow *, /**< *LOCKED* flow */ + uint8_t flags, File *, const Signature *, const SigMatchCtx *); + + /** InspectionBuffer transformation callback */ + void (*Transform)(InspectionBuffer *, void *context); + bool (*TransformValidate)(const uint8_t *content, uint16_t content_len, void *context); + + /** keyword setup function pointer */ + int (*Setup)(DetectEngineCtx *, Signature *, const char *); + + bool (*SupportsPrefilter)(const Signature *s); + int (*SetupPrefilter)(DetectEngineCtx *de_ctx, struct SigGroupHead_ *sgh); + + void (*Free)(DetectEngineCtx *, void *); +#ifdef UNITTESTS + void (*RegisterTests)(void); +#endif + uint16_t flags; + /* coccinelle: SigTableElmt:flags:SIGMATCH_ */ + + /** better keyword to replace the current one */ + uint16_t alternative; + + const char *name; /**< keyword name alias */ + const char *alias; /**< name alias */ + const char *desc; + const char *url; + +} SigTableElmt; + +/* event code */ +enum { + FILE_DECODER_EVENT_NO_MEM, + FILE_DECODER_EVENT_INVALID_SWF_LENGTH, + FILE_DECODER_EVENT_INVALID_SWF_VERSION, + FILE_DECODER_EVENT_Z_DATA_ERROR, + FILE_DECODER_EVENT_Z_STREAM_ERROR, + FILE_DECODER_EVENT_Z_BUF_ERROR, + FILE_DECODER_EVENT_Z_UNKNOWN_ERROR, + FILE_DECODER_EVENT_LZMA_IO_ERROR, + FILE_DECODER_EVENT_LZMA_HEADER_TOO_SHORT_ERROR, + FILE_DECODER_EVENT_LZMA_DECODER_ERROR, + FILE_DECODER_EVENT_LZMA_MEMLIMIT_ERROR, + FILE_DECODER_EVENT_LZMA_XZ_ERROR, + FILE_DECODER_EVENT_LZMA_UNKNOWN_ERROR, + + DETECT_EVENT_TOO_MANY_BUFFERS, +}; + +#define SIG_GROUP_HEAD_HAVERAWSTREAM BIT_U32(0) +#ifdef HAVE_MAGIC +#define SIG_GROUP_HEAD_HAVEFILEMAGIC BIT_U32(20) +#endif +#define SIG_GROUP_HEAD_HAVEFILEMD5 BIT_U32(21) +#define SIG_GROUP_HEAD_HAVEFILESIZE BIT_U32(22) +#define SIG_GROUP_HEAD_HAVEFILESHA1 BIT_U32(23) +#define SIG_GROUP_HEAD_HAVEFILESHA256 BIT_U32(24) + +enum MpmBuiltinBuffers { + MPMB_TCP_PKT_TS, + MPMB_TCP_PKT_TC, + MPMB_TCP_STREAM_TS, + MPMB_TCP_STREAM_TC, + MPMB_UDP_TS, + MPMB_UDP_TC, + MPMB_OTHERIP, + MPMB_MAX, +}; + +typedef struct MpmStore_ { + uint8_t *sid_array; + uint32_t sid_array_size; + + int direction; + enum MpmBuiltinBuffers buffer; + int sm_list; + int32_t sgh_mpm_context; + AppProto alproto; + MpmCtx *mpm_ctx; + +} MpmStore; + +typedef void (*PrefilterFrameFn)(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, + const struct Frames *frames, const struct Frame *frame); + +typedef struct AppLayerTxData AppLayerTxData; +typedef void (*PrefilterTxFn)(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f, + void *tx, const uint64_t tx_id, const AppLayerTxData *tx_data, const uint8_t flags); + +typedef struct PrefilterEngineList_ { + uint16_t id; + + /** App Proto this engine applies to: only used with Tx Engines */ + AppProto alproto; + /** Minimal Tx progress we need before running the engine. Only used + * with Tx Engine */ + uint8_t tx_min_progress; + + uint8_t frame_type; + + /** Context for matching. Might be MpmCtx for MPM engines, other ctx' + * for other engines. */ + void *pectx; + + void (*Prefilter)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx); + PrefilterTxFn PrefilterTx; + PrefilterFrameFn PrefilterFrame; + + struct PrefilterEngineList_ *next; + + /** Free function for pectx data. If NULL the memory is not freed. */ + void (*Free)(void *pectx); + + const char *name; + /* global id for this prefilter */ + uint32_t gid; +} PrefilterEngineList; + +typedef struct PrefilterEngine_ { + uint16_t local_id; + + /** App Proto this engine applies to: only used with Tx Engines */ + AppProto alproto; + + union { + /** Minimal Tx progress we need before running the engine. Only used + * with Tx Engine */ + uint8_t tx_min_progress; + uint8_t frame_type; + } ctx; + + /** Context for matching. Might be MpmCtx for MPM engines, other ctx' + * for other engines. */ + void *pectx; + + union { + void (*Prefilter)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx); + PrefilterTxFn PrefilterTx; + PrefilterFrameFn PrefilterFrame; + } cb; + + /* global id for this prefilter */ + uint32_t gid; + bool is_last; + bool is_last_for_progress; +} PrefilterEngine; + +typedef struct SigGroupHeadInitData_ { + MpmStore mpm_store[MPMB_MAX]; + + uint8_t *sig_array; /**< bit array of sig nums (internal id's) */ + uint32_t sig_size; /**< size in bytes */ + + uint8_t protos[256]; /**< proto(s) this sgh is for */ + uint32_t direction; /**< set to SIG_FLAG_TOSERVER, SIG_FLAG_TOCLIENT or both */ + int whitelist; /**< try to make this group a unique one */ + + MpmCtx **app_mpms; + MpmCtx **pkt_mpms; + MpmCtx **frame_mpms; + + PrefilterEngineList *pkt_engines; + PrefilterEngineList *payload_engines; + PrefilterEngineList *tx_engines; + PrefilterEngineList *frame_engines; + + /** number of sigs in this group */ + SigIntId sig_cnt; + + /** Array with sig ptrs... size is sig_cnt * sizeof(Signature *) */ + Signature **match_array; + + /* port ptr */ + struct DetectPort_ *port; +} SigGroupHeadInitData; + +/** \brief Container for matching data for a signature group */ +typedef struct SigGroupHead_ { + uint32_t flags; + /* coccinelle: SigGroupHead:flags:SIG_GROUP_HEAD_ */ + + /* non prefilter list excluding SYN rules */ + uint32_t non_pf_other_store_cnt; + uint32_t non_pf_syn_store_cnt; + SignatureNonPrefilterStore *non_pf_other_store_array; // size is non_mpm_store_cnt * sizeof(SignatureNonPrefilterStore) + /* non mpm list including SYN rules */ + SignatureNonPrefilterStore *non_pf_syn_store_array; // size is non_mpm_syn_store_cnt * sizeof(SignatureNonPrefilterStore) + + /** the number of signatures in this sgh that have the filestore keyword + * set. */ + uint16_t filestore_cnt; + + uint32_t id; /**< unique id used to index sgh_array for stats */ + + PrefilterEngine *pkt_engines; + PrefilterEngine *payload_engines; + PrefilterEngine *tx_engines; + PrefilterEngine *frame_engines; + + /* ptr to our init data we only use at... init :) */ + SigGroupHeadInitData *init; + +} SigGroupHead; + +/** sigmatch has no options, so the parser shouldn't expect any */ +#define SIGMATCH_NOOPT BIT_U16(0) +/** sigmatch is compatible with a ip only rule */ +#define SIGMATCH_IPONLY_COMPAT BIT_U16(1) +/** sigmatch is compatible with a decode event only rule */ +#define SIGMATCH_DEONLY_COMPAT BIT_U16(2) +/**< Flag to indicate that the signature is not built-in */ +#define SIGMATCH_NOT_BUILT BIT_U16(3) +/** sigmatch may have options, so the parser should be ready to + * deal with both cases */ +#define SIGMATCH_OPTIONAL_OPT BIT_U16(4) +/** input may be wrapped in double quotes. They will be stripped before + * input data is passed to keyword parser */ +#define SIGMATCH_QUOTES_OPTIONAL BIT_U16(5) +/** input MUST be wrapped in double quotes. They will be stripped before + * input data is passed to keyword parser. Missing double quotes lead to + * error and signature invalidation. */ +#define SIGMATCH_QUOTES_MANDATORY BIT_U16(6) +/** negation parsing is handled by the rule parser. Signature::init_data::negated + * will be set to true or false prior to calling the keyword parser. Exclamation + * mark is stripped from the input to the keyword parser. */ +#define SIGMATCH_HANDLE_NEGATION BIT_U16(7) +/** keyword is a content modifier */ +#define SIGMATCH_INFO_CONTENT_MODIFIER BIT_U16(8) +/** keyword is a sticky buffer */ +#define SIGMATCH_INFO_STICKY_BUFFER BIT_U16(9) +/** keyword is deprecated: used to suggest an alternative */ +#define SIGMATCH_INFO_DEPRECATED BIT_U16(10) +/** strict parsing is enabled */ +#define SIGMATCH_STRICT_PARSING BIT_U16(11) + +enum DetectEngineTenantSelectors +{ + TENANT_SELECTOR_UNKNOWN = 0, /**< not set */ + TENANT_SELECTOR_DIRECT, /**< method provides direct tenant id */ + TENANT_SELECTOR_VLAN, /**< map vlan to tenant id */ + TENANT_SELECTOR_LIVEDEV, /**< map livedev to tenant id */ +}; + +typedef struct DetectEngineTenantMapping_ { + uint32_t tenant_id; + + /* traffic id that maps to the tenant id */ + uint32_t traffic_id; + + struct DetectEngineTenantMapping_ *next; +} DetectEngineTenantMapping; + +typedef struct DetectEngineMasterCtx_ { + SCMutex lock; + + /** enable multi tenant mode */ + int multi_tenant_enabled; + + /** version, incremented after each 'apply to threads' */ + uint32_t version; + + /** list of active detection engines. This list is used to generate the + * threads det_ctx's */ + DetectEngineCtx *list; + + /** free list, containing detection engines that will be removed but may + * still be referenced by det_ctx's. Freed as soon as all references are + * gone. */ + DetectEngineCtx *free_list; + + enum DetectEngineTenantSelectors tenant_selector; + + /** list of tenant mappings. Updated under lock. Used to generate lookup + * structures. */ + DetectEngineTenantMapping *tenant_mapping_list; + + /** list of keywords that need thread local ctxs, + * only updated by keyword registration at start up. Not + * covered by the lock. */ + DetectEngineThreadKeywordCtxItem *keyword_list; + int keyword_id; +} DetectEngineMasterCtx; + +/* Table with all SigMatch registrations */ +extern SigTableElmt sigmatch_table[DETECT_TBLSIZE]; + +/** Remember to add the options in SignatureIsIPOnly() at detect.c otherwise it wont be part of a signature group */ + +/* detection api */ +TmEcode Detect(ThreadVars *tv, Packet *p, void *data); + +SigMatch *SigMatchAlloc(void); +Signature *SigFindSignatureBySidGid(DetectEngineCtx *, uint32_t, uint32_t); +void SigMatchFree(DetectEngineCtx *, SigMatch *sm); + +void SigRegisterTests(void); + +void DisableDetectFlowFileFlags(Flow *f); +char *DetectLoadCompleteSigPath(const DetectEngineCtx *, const char *sig_file); +int SigLoadSignatures (DetectEngineCtx *, char *, int); +void SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, Packet *p); + +int SignatureIsIPOnly(DetectEngineCtx *de_ctx, const Signature *s); +const SigGroupHead *SigMatchSignaturesGetSgh(const DetectEngineCtx *de_ctx, const Packet *p); + +int DetectUnregisterThreadCtxFuncs(DetectEngineCtx *, void *data, const char *name); +int DetectRegisterThreadCtxFuncs(DetectEngineCtx *, const char *name, void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *), int); +void *DetectThreadCtxGetKeywordThreadCtx(DetectEngineThreadCtx *, int); + +void RuleMatchCandidateTxArrayInit(DetectEngineThreadCtx *det_ctx, uint32_t size); +void RuleMatchCandidateTxArrayFree(DetectEngineThreadCtx *det_ctx); + +void AlertQueueInit(DetectEngineThreadCtx *det_ctx); +void AlertQueueFree(DetectEngineThreadCtx *det_ctx); +void AlertQueueAppend(DetectEngineThreadCtx *det_ctx, const Signature *s, Packet *p, uint64_t tx_id, + uint8_t alert_flags); + +int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx); + +int DetectMetadataHashInit(DetectEngineCtx *de_ctx); +void DetectMetadataHashFree(DetectEngineCtx *de_ctx); + +/* events */ +void DetectEngineSetEvent(DetectEngineThreadCtx *det_ctx, uint8_t e); +AppLayerDecoderEvents *DetectEngineGetEvents(DetectEngineThreadCtx *det_ctx); + +void DumpPatterns(DetectEngineCtx *de_ctx); + + +#endif /* __DETECT_H__ */ + |