/* Copyright (C) 2007-2014 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 <stdint.h>

#include "flow.h"

#include "detect-engine-proto.h"
#include "detect-reference.h"

#include "packet-queue.h"
#include "util-mpm.h"
#include "util-hash.h"
#include "util-hashlist.h"
#include "util-debug.h"
#include "util-error.h"
#include "util-radix-tree.h"
#include "util-file.h"
#include "reputation.h"

#include "detect-mark.h"

#define DETECT_MAX_RULE_SIZE 8192

/* forward declarations for the structures from detect-engine-sigorder.h */
struct SCSigOrderFunc_;
struct SCSigSignatureWrapper_;

/*

  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
   -=- Src address
   -==- Dst address
   -===- Src port
   -====- Dst port

   For the other protocols

   - Flow direction
   -- Protocol
   -=- Src address
   -==- Dst address

*/

/*
 * DETECT ADDRESS
 */

/* holds the values for different possible lists in struct Signature.
 * These codes are access points to particular lists in the array
 * Signature->sm_lists[DETECT_SM_LIST_MAX]. */
enum DetectSigmatchListEnum {
    DETECT_SM_LIST_MATCH = 0,
    DETECT_SM_LIST_PMATCH,
    /* list for http_uri keyword and the ones relative to it */
    DETECT_SM_LIST_UMATCH,
    /* list for http_raw_uri keyword and the ones relative to it */
    DETECT_SM_LIST_HRUDMATCH,
    /* list for http_client_body keyword and the ones relative to it */
    DETECT_SM_LIST_HCBDMATCH,
    /* list for http_server_body keyword and the ones relative to it */
    DETECT_SM_LIST_HSBDMATCH,
    /* list for http_header keyword and the ones relative to it */
    DETECT_SM_LIST_HHDMATCH,
    /* list for http_raw_header keyword and the ones relative to it */
    DETECT_SM_LIST_HRHDMATCH,
    /* list for http_stat_msg keyword and the ones relative to it */
    DETECT_SM_LIST_HSMDMATCH,
    /* list for http_stat_code keyword and the ones relative to it */
    DETECT_SM_LIST_HSCDMATCH,
    /* list for http_host keyword and the ones relative to it */
    DETECT_SM_LIST_HHHDMATCH,
    /* list for http_raw_host keyword and the ones relative to it */
    DETECT_SM_LIST_HRHHDMATCH,
    /* list for http_method keyword and the ones relative to it */
    DETECT_SM_LIST_HMDMATCH,
    /* list for http_cookie keyword and the ones relative to it */
    DETECT_SM_LIST_HCDMATCH,
    /* list for http_user_agent keyword and the ones relative to it */
    DETECT_SM_LIST_HUADMATCH,
    /* app event engine sm list */
    DETECT_SM_LIST_APP_EVENT,

    DETECT_SM_LIST_AMATCH,
    DETECT_SM_LIST_DMATCH,
    DETECT_SM_LIST_TMATCH,

    DETECT_SM_LIST_FILEMATCH,

    DETECT_SM_LIST_DNSQUERY_MATCH,
    DETECT_SM_LIST_MODBUS_MATCH,

    /* list for post match actions: flowbit set, flowint increment, etc */
    DETECT_SM_LIST_POSTMATCH,

    /* lists for alert thresholding and suppression */
    DETECT_SM_LIST_SUPPRESS,
    DETECT_SM_LIST_THRESHOLD,
    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 */
    DETECT_SM_LIST_NOTSET,
};

/* 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_ANY            0x01 /**< address is "any" */
#define ADDRESS_FLAG_NOT            0x02 /**< address is negated */

#define ADDRESS_SIGGROUPHEAD_COPY   0x04 /**< sgh is a ptr to another sgh */
#define ADDRESS_PORTS_COPY          0x08 /**< ports are a ptr to other ports */
#define ADDRESS_PORTS_NOTUNIQ       0x10
#define ADDRESS_HAVEPORT            0x20 /**< address has a ports ptr */

/** \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;
//    uint8_t family; /**< address family, AF_INET (IPv4) or AF_INET6 (IPv6) */
//    uint32_t ip[4]; /**< the address, or lower end of a range */
//    uint32_t ip2[4]; /**< higher end of a range */

    /** ptr to the next address (dst addr in that case) or to the src port */
    union {
        struct DetectAddressHead_ *dst_gh; /**< destination address */
        struct DetectPort_ *port; /**< source port */
    };

    /** signatures that belong in this group */
    struct SigGroupHead_ *sh;

    /** 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;

    uint32_t cnt;
} DetectAddress;

/** Signature grouping head. Here 'any', ipv4 and ipv6 are split out */
typedef struct DetectAddressHead_ {
    DetectAddress *any_head;
    DetectAddress *ipv4_head;
    DetectAddress *ipv6_head;
} DetectAddressHead;


#include "detect-threshold.h"

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 */
#define PORT_GROUP_PORTS_COPY   0x08 /**< dst_ph is a ptr copy */

/** \brief Port structure for detection engine */
typedef struct DetectPort_ {
    uint16_t port;
    uint16_t port2;

    /* signatures that belong in this group */
    struct SigGroupHead_ *sh;

    struct DetectPort_ *dst_ph;

    /* double linked list */
    union {
        struct DetectPort_ *prev;
        struct DetectPort_ *hnext; /* hash next */
    };
    struct DetectPort_ *next;

    uint32_t cnt;
    uint8_t flags;  /**< flags for this port */
} DetectPort;

/* Signature flags */
#define SIG_FLAG_SRC_ANY                (1)  /**< source is any */
#define SIG_FLAG_DST_ANY                (1<<1)  /**< destination is any */
#define SIG_FLAG_SP_ANY                 (1<<2)  /**< source port is any */
#define SIG_FLAG_DP_ANY                 (1<<3)  /**< destination port is any */

#define SIG_FLAG_NOALERT                (1<<4)  /**< no alert flag is set */
#define SIG_FLAG_DSIZE                  (1<<5)  /**< signature has a dsize setting */
#define SIG_FLAG_APPLAYER               (1<<6)  /**< signature applies to app layer instead of packets */
#define SIG_FLAG_IPONLY                 (1<<7) /**< ip only signature */

#define SIG_FLAG_STATE_MATCH            (1<<8) /**< signature has matches that require stateful inspection */

#define SIG_FLAG_REQUIRE_PACKET         (1<<9) /**< signature is requiring packet match */
#define SIG_FLAG_REQUIRE_STREAM         (1<<10) /**< signature is requiring stream match */

#define SIG_FLAG_MPM_PACKET             (1<<11)
#define SIG_FLAG_MPM_PACKET_NEG         (1<<12)
#define SIG_FLAG_MPM_STREAM             (1<<13)
#define SIG_FLAG_MPM_STREAM_NEG         (1<<14)
#define SIG_FLAG_MPM_APPLAYER           (1<<15)
#define SIG_FLAG_MPM_APPLAYER_NEG       (1<<16)

#define SIG_FLAG_REQUIRE_FLOWVAR        (1<<17) /**< signature can only match if a flowbit, flowvar or flowint is available. */

#define SIG_FLAG_FILESTORE              (1<<18) /**< signature has filestore keyword */

#define SIG_FLAG_TOSERVER               (1<<19)
#define SIG_FLAG_TOCLIENT               (1<<20)

#define SIG_FLAG_TLSSTORE               (1<<21)

/* signature init flags */
#define SIG_FLAG_INIT_DEONLY         1  /**< decode event only signature */
#define SIG_FLAG_INIT_PACKET         (1<<1)  /**< signature has matches against a packet (as opposed to app layer) */
#define SIG_FLAG_INIT_FLOW           (1<<2)  /**< signature has a flow setting */
#define SIG_FLAG_INIT_BIDIREC        (1<<3)  /**< signature has bidirectional operator */
#define SIG_FLAG_INIT_PAYLOAD        (1<<4)  /**< signature is inspecting the packet payload */
#define SIG_FLAG_INIT_FIRST_IPPROTO_SEEN (1 << 5) /** < signature has seen the first ip_proto keyword */

/* signature mask flags */
#define SIG_MASK_REQUIRE_PAYLOAD            (1<<0)
#define SIG_MASK_REQUIRE_FLOW               (1<<1)
#define SIG_MASK_REQUIRE_FLAGS_INITDEINIT   (1<<2)    /* SYN, FIN, RST */
#define SIG_MASK_REQUIRE_FLAGS_UNUSUAL      (1<<3)    /* URG, ECN, CWR */
#define SIG_MASK_REQUIRE_NO_PAYLOAD         (1<<4)
#define SIG_MASK_REQUIRE_HTTP_STATE         (1<<5)
#define SIG_MASK_REQUIRE_DCE_STATE          (1<<6)
#define SIG_MASK_REQUIRE_ENGINE_EVENT       (1<<7)

/* for now a uint8_t is enough */
#define SignatureMask uint8_t

#define DETECT_ENGINE_THREAD_CTX_INSPECTING_PACKET 0x0001
#define DETECT_ENGINE_THREAD_CTX_INSPECTING_STREAM 0x0002
#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_TYPE          0x04
#define FILE_SIG_NEED_MAGIC         0x08    /**< need the start of the file */
#define FILE_SIG_NEED_FILECONTENT   0x10
#define FILE_SIG_NEED_MD5           0x20
#define FILE_SIG_NEED_SIZE          0x40

/* Detection Engine flags */
#define DE_QUIET           0x01     /**< DE is quiet (esp for unittests) */

typedef struct IPOnlyCIDRItem_ {
    /* address data for this item */
    uint8_t family;
    uint32_t ip[4];
    /* netmask in CIDR values (ex. /16 /18 /24..) */
    uint8_t netmask;

    /* If this host or net is negated for the signum */
    uint8_t negated;
    SigIntId signum; /**< our internal id */

    /* linked list, the header should be the biggest network */
    struct IPOnlyCIDRItem_ *next;

} IPOnlyCIDRItem;

/** \brief Subset of the Signature for cache efficient prefiltering
 */
typedef struct SignatureHeader_ {
    union {
        struct {
            /* coccinelle: SignatureHeader:flags:SIG_FLAG */
            uint32_t flags;
            AppProto alproto;
            uint16_t dsize_low;
        };
        uint64_t hdr_copy1;
    };
    union {
        struct {
            uint16_t dsize_high;
            uint16_t mpm_pattern_id_div_8;
        };
        uint32_t hdr_copy2;
    };
    union {
        struct {
            uint8_t mpm_pattern_id_mod_8;
            SignatureMask mask;
            SigIntId num; /**< signature number, internal id */
        };
        uint32_t hdr_copy3;
    };
    /** pointer to the full signature */
    struct Signature_ *full_sig;
} SignatureHeader;

/** \brief a single match condition for a signature */
typedef struct SigMatch_ {
    uint16_t idx; /**< position in the signature */
    uint8_t type; /**< match type */
    void *ctx; /**< plugin specific data */
    struct SigMatch_ *next;
    struct SigMatch_ *prev;
} SigMatch;

/** \brief Signature container */
typedef struct Signature_ {
    union {
        struct {
            /* coccinelle: Signature:flags:SIG_FLAG */
            uint32_t flags;
            AppProto alproto;
            uint16_t dsize_low;
        };
        uint64_t hdr_copy1;
    };
    union {
        struct {
            uint16_t dsize_high;
            uint16_t mpm_pattern_id_div_8;
        };
        uint32_t hdr_copy2;
    };
    union {
        struct {
            uint8_t mpm_pattern_id_mod_8;
            SignatureMask mask;
            SigIntId num; /**< signature number, internal id */
        };
        uint32_t hdr_copy3;
    };

    /** inline -- action */
    uint8_t action;
    uint8_t file_flags;

    /** ipv4 match arrays */
    uint16_t addr_dst_match4_cnt;
    uint16_t addr_src_match4_cnt;
    DetectMatchAddressIPv4 *addr_dst_match4;
    DetectMatchAddressIPv4 *addr_src_match4;
    /** ipv6 match arrays */
    DetectMatchAddressIPv6 *addr_dst_match6;
    DetectMatchAddressIPv6 *addr_src_match6;
    uint16_t addr_dst_match6_cnt;
    uint16_t addr_src_match6_cnt;

    uint32_t id;  /**< sid, set by the 'sid' rule keyword */
    /** port settings for this signature */
    DetectPort *sp, *dp;

    /** addresses, ports and proto this sig matches on */
    DetectProto proto;

    /** classification id **/
    uint8_t class;

#ifdef PROFILING
    uint16_t profiling_id;
#endif

    uint32_t gid; /**< generator id */

    /** netblocks and hosts specified at the sid, in CIDR format */
    IPOnlyCIDRItem *CidrSrc, *CidrDst;

    uint32_t rev;

    int prio;

    /* holds all sm lists */
    struct SigMatch_ *sm_lists[DETECT_SM_LIST_MAX];
    /* holds all sm lists' tails */
    struct SigMatch_ *sm_lists_tail[DETECT_SM_LIST_MAX];

    SigMatch *filestore_sm;

    char *msg;

    /** classification message */
    char *class_msg;
    /** Reference */
    DetectReference *references;

    /** address settings for this signature */
    DetectAddressHead src, dst;

    /* used to hold flags that are predominantly used during init */
    uint32_t init_flags;
    /* coccinelle: Signature:init_flags:SIG_FLAG_INIT_ */

    /** number of sigmatches in the match and pmatch list */
    uint16_t sm_cnt;
    /* used at init to determine max dsize */
    SigMatch *dsize_sm;
    /* the fast pattern added from this signature */
    SigMatch *mpm_sm;
    /* helper for init phase */
    uint16_t mpm_content_maxlen;
    uint16_t mpm_uricontent_maxlen;

    /* Be careful, this pointer is only valid while parsing the sig,
     * to warn the user about any possible problem */
    char *sig_str;

    int list;

    /** ptr to the next sig in the list */
    struct Signature_ *next;
} Signature;

typedef struct DetectReplaceList_ {
    struct DetectContentData_ *cd;
    uint8_t *found;
    struct DetectReplaceList_ *next;
} DetectReplaceList;

/** only execute flowvar storage if rule matched */
#define DETECT_FLOWVAR_TYPE_POSTMATCH   1
/** execute flowvar storage even if rule doesn't match (for luajit) */
#define DETECT_FLOWVAR_TYPE_ALWAYS      2

/** list for flowvar store candidates, to be stored from
 *  post-match function */
typedef struct DetectFlowvarList_ {
    uint16_t idx;                       /**< flowvar name idx */
    uint16_t len;                       /**< data len */
    uint8_t *buffer;                    /**< alloc'd buffer, may be freed by
                                             post-match, post-non-match */
    int type;                           /**< type of store candidate POSTMATCH or ALWAYS */
    struct DetectFlowvarList_ *next;
} DetectFlowvarList;

typedef struct DetectEngineIPOnlyThreadCtx_ {
    uint8_t *sig_match_array; /* bit array of sig nums */
    uint32_t sig_match_size;  /* size in bytes of the array */
} DetectEngineIPOnlyThreadCtx;

/** \brief IP only rules matching ctx.
 *  \todo a radix tree would be great here */
typedef struct DetectEngineIPOnlyCtx_ {
    /* lookup hashes */
    HashListTable *ht16_src, *ht16_dst;
    HashListTable *ht24_src, *ht24_dst;

    /* Lookup trees */
    SCRadixTree *tree_ipv4src, *tree_ipv4dst;
    SCRadixTree *tree_ipv6src, *tree_ipv6dst;

    /* Used to build the radix trees */
    IPOnlyCIDRItem *ip_src, *ip_dst;

    /* counters */
    uint32_t a_src_uniq16, a_src_total16;
    uint32_t a_dst_uniq16, a_dst_total16;
    uint32_t a_src_uniq24, a_src_total24;
    uint32_t a_dst_uniq24, a_dst_total24;

    uint32_t max_idx;

    uint8_t *sig_init_array; /* bit array of sig nums */
    uint32_t sig_init_size;  /* size in bytes of the array */

    /* number of sigs in this head */
    uint32_t sig_cnt;
    uint32_t *match_array;
} DetectEngineIPOnlyCtx;

typedef struct DetectEngineLookupFlow_ {
    DetectAddressHead *src_gh[256]; /* a head for each protocol */
    DetectAddressHead *tmp_gh[256];
} DetectEngineLookupFlow;

/* Flow status
 *
 * to server
 * to client
 */
#define FLOW_STATES 2

/* mpm pattern id api */
typedef struct MpmPatternIdStore_ {
    HashTable *hash;
    PatIntId max_id;

    uint32_t unique_patterns;
    uint32_t shared_patterns;
} MpmPatternIdStore;

/** \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 DetectEngineThreadKeywordCtxItem_ {
    void *(*InitFunc)(void *);
    void (*FreeFunc)(void *);
    void *data;
    struct DetectEngineThreadKeywordCtxItem_ *next;
    int id;
    const char *name; /* keyword name, for error printing */
} DetectEngineThreadKeywordCtxItem;

/** \brief main detection engine ctx */
typedef struct DetectEngineCtx_ {
    uint8_t flags;
    int failure_fatal;

    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;

    /* used by the signature ordering module */
    struct SCSigOrderFunc_ *sc_sig_order_funcs;

    /* hash table used for holding the classification config info */
    HashTable *class_conf_ht;
    /* hash table used for holding the reference config info */
    HashTable *reference_conf_ht;

    /* main sigs */
    DetectEngineLookupFlow flow_gh[FLOW_STATES];

    uint32_t mpm_unique, mpm_reuse, mpm_none,
        mpm_uri_unique, mpm_uri_reuse, mpm_uri_none;
    uint32_t gh_unique, gh_reuse;

    uint32_t mpm_max_patcnt, mpm_min_patcnt, mpm_tot_patcnt,
        mpm_uri_max_patcnt, mpm_uri_min_patcnt, mpm_uri_tot_patcnt;

    /* init phase vars */
    HashListTable *sgh_hash_table;

    HashListTable *sgh_mpm_hash_table;
    HashListTable *sgh_mpm_uri_hash_table;
    HashListTable *sgh_mpm_stream_hash_table;

    HashListTable *sgh_sport_hash_table;
    HashListTable *sgh_dport_hash_table;

    HashListTable *sport_hash_table;
    HashListTable *dport_hash_table;

    HashListTable *variable_names;
    HashListTable *variable_idxs;
    uint16_t variable_names_idx;

    /* hash table used to cull out duplicate sigs */
    HashListTable *dup_sig_hash_table;

    /* memory counters */
    uint32_t mpm_memory_size;

    DetectEngineIPOnlyCtx io_ctx;
    ThresholdCtx ths_ctx;

    uint16_t mpm_matcher; /**< mpm matcher this ctx uses */

    /* Config options */

    uint16_t max_uniq_toclient_src_groups;
    uint16_t max_uniq_toclient_dst_groups;
    uint16_t max_uniq_toclient_sp_groups;
    uint16_t max_uniq_toclient_dp_groups;

    uint16_t max_uniq_toserver_src_groups;
    uint16_t max_uniq_toserver_dst_groups;
    uint16_t max_uniq_toserver_sp_groups;
    uint16_t max_uniq_toserver_dp_groups;
/*
    uint16_t max_uniq_small_toclient_src_groups;
    uint16_t max_uniq_small_toclient_dst_groups;
    uint16_t max_uniq_small_toclient_sp_groups;
    uint16_t max_uniq_small_toclient_dp_groups;

    uint16_t max_uniq_small_toserver_src_groups;
    uint16_t max_uniq_small_toserver_dst_groups;
    uint16_t max_uniq_small_toserver_sp_groups;
    uint16_t max_uniq_small_toserver_dp_groups;
*/

    /* specify the configuration for mpm context factory */
    uint8_t sgh_mpm_context;

    /** hash table for looking up patterns for
     *  id sharing and id tracking. */
    MpmPatternIdStore *mpm_pattern_id_store;
    uint16_t max_fp_id;

    MpmCtxFactoryContainer *mpm_ctx_factory_container;

    /* maximum recursion depth for content inspection */
    int inspection_recursion_limit;

    /* conf parameter that limits the length of the http request body inspected */
    int hcbd_buffer_limit;
    /* conf parameter that limits the length of the http response body inspected */
    int hsbd_buffer_limit;

    /* 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;
    int32_t sgh_mpm_context_uri;
    int32_t sgh_mpm_context_hcbd;
    int32_t sgh_mpm_context_hsbd;
    int32_t sgh_mpm_context_hhd;
    int32_t sgh_mpm_context_hrhd;
    int32_t sgh_mpm_context_hmd;
    int32_t sgh_mpm_context_hcd;
    int32_t sgh_mpm_context_hrud;
    int32_t sgh_mpm_context_hsmd;
    int32_t sgh_mpm_context_hscd;
    int32_t sgh_mpm_context_huad;
    int32_t sgh_mpm_context_hhhd;
    int32_t sgh_mpm_context_hrhhd;
    int32_t sgh_mpm_context_app_proto_detect;
    int32_t sgh_mpm_context_dnsquery;

    /* the max local id used amongst all sigs */
    int32_t byte_extract_max_local_id;

    /* id used by every detect engine ctx instance */
    uint32_t id;

    /** 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;

    /** Store rule file and line so that parsers can use them in errors. */
    char *rule_file;
    int rule_line;

    /** Is detect engine using a delayed init */
    int delayed_detect;
    /** Did we load the signatures? */
    int delayed_detect_initialized;

    /** list of keywords that need thread local ctxs */
    DetectEngineThreadKeywordCtxItem *keyword_list;
    int keyword_id;

    int detect_luajit_instances;

#ifdef PROFILING
    struct SCProfileDetectCtx_ *profile_ctx;
    struct SCProfileKeywordDetectCtx_ *profile_keyword_ctx;
    struct SCProfileKeywordDetectCtx_ *profile_keyword_ctx_per_list[DETECT_SM_LIST_MAX];
#endif
} DetectEngineCtx;

/* Engine groups profiles (low, medium, high, custom) */
enum {
    ENGINE_PROFILE_UNKNOWN,
    ENGINE_PROFILE_LOW,
    ENGINE_PROFILE_MEDIUM,
    ENGINE_PROFILE_HIGH,
    ENGINE_PROFILE_CUSTOM,
    ENGINE_PROFILE_MAX
};

/* Siggroup mpm context profile */
enum {
    ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL,
    ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE,
    ENGINE_SGH_MPM_FACTORY_CONTEXT_AUTO
};

typedef struct HttpReassembledBody_ {
    uint8_t *buffer;
    uint32_t buffer_size;   /**< size of the buffer itself */
    uint32_t buffer_len;    /**< data len in the buffer */
    uint64_t offset;        /**< data offset */
} HttpReassembledBody;

#define DETECT_FILESTORE_MAX 15
/** \todo review how many we actually need here */
#define DETECT_SMSG_PMQ_NUM 256

/**
  * Detection engine thread data.
  */
typedef struct DetectionEngineThreadCtx_ {
    /* the thread to which this detection engine thread belongs */
    ThreadVars *tv;

    /* detection engine variables */

    /** 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;

    HttpReassembledBody *hsbd;
    uint64_t hsbd_start_tx_id;
    uint16_t hsbd_buffers_size;
    uint16_t hsbd_buffers_list_len;

    HttpReassembledBody *hcbd;
    uint64_t hcbd_start_tx_id;
    uint16_t hcbd_buffers_size;
    uint16_t hcbd_buffers_list_len;

    uint8_t **hhd_buffers;
    uint32_t *hhd_buffers_len;
    uint16_t hhd_buffers_size;
    uint16_t hhd_buffers_list_len;
    uint64_t hhd_start_tx_id;

    /** id for alert counter */
    uint16_t counter_alerts;

    /* used to discontinue any more matching */
    uint16_t discontinue_matching;
    uint16_t flags;

    /* bool: if tx_id is set, this is 1, otherwise 0 */
    uint16_t tx_id_set;
    /** ID of the transaction currently being inspected. */
    uint64_t tx_id;

    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;

    /** Array of sigs that had a state change */
    SigIntId de_state_sig_array_len;
    uint8_t *de_state_sig_array;

    struct SigGroupHead_ *sgh;
    /** 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 */
    PatternMatcherQueue pmq;
    PatternMatcherQueue smsg_pmq[DETECT_SMSG_PMQ_NUM];

    /** ip only rules ctx */
    DetectEngineIPOnlyThreadCtx io_ctx;

    /* byte jump values */
    uint64_t *bj_values;

    /* string to replace */
    DetectReplaceList *replist;
    /* flowvars to store in post match function */
    DetectFlowvarList *flowvarlist;

    /* 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 {
        uint16_t file_id;
        uint64_t tx_id;
    } filestore[DETECT_FILESTORE_MAX];

    DetectEngineCtx *de_ctx;
    /** store for keyword contexts that need a per thread storage because of
     *  thread safety issues */
    void **keyword_ctxs_array;
    int keyword_ctxs_size;

#ifdef PROFILING
    struct SCProfileData_ *rule_perf_data;
    int rule_perf_data_size;
    struct SCProfileKeywordData_ *keyword_perf_data;
    struct SCProfileKeywordData_ *keyword_perf_data_per_list[DETECT_SM_LIST_MAX];
    int keyword_perf_list; /**< list we're currently inspecting, DETECT_SM_LIST_* */
#endif
} DetectEngineThreadCtx;

/** \brief element in sigmatch type table.
 *  \note FileMatch pointer below takes a locked flow, AppLayerMatch an unlocked flow
 */
typedef struct SigTableElmt_ {
    /** Packet match function pointer */
    int (*Match)(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature *, SigMatch *);

    /** AppLayer match function  pointer */
    int (*AppLayerMatch)(ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t flags, void *alstate, Signature *, SigMatch *);

    /** File match function  pointer */
    int (*FileMatch)(ThreadVars *,  /**< thread local vars */
        DetectEngineThreadCtx *,
        Flow *,                     /**< *LOCKED* flow */
        uint8_t flags, File *, Signature *, SigMatch *);

    /** app layer proto from app-layer-protos.h this match applies to */
    AppProto alproto;

    /** keyword setup function pointer */
    int (*Setup)(DetectEngineCtx *, Signature *, char *);

    void (*Free)(void *);
    void (*RegisterTests)(void);

    uint8_t flags;
    char *name;     /**< keyword name alias */
    char *alias;    /**< name alias */
    char *desc;
    char *url;

} SigTableElmt;

#define SIG_GROUP_HEAD_MPM_URI          (1)
#define SIG_GROUP_HEAD_MPM_HCBD         (1 << 1)
#define SIG_GROUP_HEAD_MPM_HHD          (1 << 2)
#define SIG_GROUP_HEAD_MPM_HRHD         (1 << 3)
#define SIG_GROUP_HEAD_MPM_HMD          (1 << 4)
#define SIG_GROUP_HEAD_MPM_HCD          (1 << 5)
#define SIG_GROUP_HEAD_MPM_HRUD         (1 << 6)
#define SIG_GROUP_HEAD_MPM_HSBD         (1 << 7)
#define SIG_GROUP_HEAD_MPM_HSMD         (1 << 8)
#define SIG_GROUP_HEAD_MPM_HSCD         (1 << 9)
#define SIG_GROUP_HEAD_MPM_HUAD         (1 << 10)
#define SIG_GROUP_HEAD_MPM_HHHD         (1 << 11)
#define SIG_GROUP_HEAD_MPM_HRHHD        (1 << 12)

#define SIG_GROUP_HEAD_MPM_COPY         (1 << 13)
#define SIG_GROUP_HEAD_MPM_URI_COPY     (1 << 14)
#define SIG_GROUP_HEAD_MPM_STREAM_COPY  (1 << 15)
#define SIG_GROUP_HEAD_FREE             (1 << 16)
#define SIG_GROUP_HEAD_MPM_PACKET       (1 << 17)
#define SIG_GROUP_HEAD_MPM_STREAM       (1 << 18)
#define SIG_GROUP_HEAD_REFERENCED       (1 << 19) /**< sgh is being referenced by others, don't clear */
#define SIG_GROUP_HEAD_HAVEFILEMAGIC    (1 << 20)
#define SIG_GROUP_HEAD_HAVEFILEMD5      (1 << 21)
#define SIG_GROUP_HEAD_HAVEFILESIZE     (1 << 22)
#define SIG_GROUP_HEAD_MPM_DNSQUERY     (1 << 23)

typedef struct SigGroupHeadInitData_ {
    /* list of content containers
     * XXX move into a separate data struct
     * with only a ptr to it. Saves some memory
     * after initialization
     */
    uint8_t *content_array;
    uint32_t content_size;
    uint8_t *uri_content_array;
    uint32_t uri_content_size;
    uint8_t *stream_content_array;
    uint32_t stream_content_size;

    /* "Normal" detection uses these only at init, but ip-only
     * uses it during runtime as well, thus not in init... */
    uint8_t *sig_array; /**< bit array of sig nums (internal id's) */
    uint32_t sig_size; /**< size in bytes */

    /* port ptr */
    struct DetectPort_ *port;
} SigGroupHeadInitData;

/** \brief Container for matching data for a signature group */
typedef struct SigGroupHead_ {
    uint32_t flags;
    /* number of sigs in this head */
    SigIntId sig_cnt;

    uint16_t mpm_content_maxlen;

    /** array of masks, used to check multiple masks against
     *  a packet using SIMD. */
#if defined(__SSE3__) || defined(__tile__)
    SignatureMask *mask_array;
#endif
    /** chunk of memory containing the "header" part of each
     *  signature ordered as an array. Used to pre-filter the
     *  signatures to be inspected in a cache efficient way. */
    SignatureHeader *head_array;

    /* pattern matcher instances */
    MpmCtx *mpm_proto_other_ctx;

    MpmCtx *mpm_proto_tcp_ctx_ts;
    MpmCtx *mpm_proto_udp_ctx_ts;
    MpmCtx *mpm_stream_ctx_ts;
    MpmCtx *mpm_uri_ctx_ts;
    MpmCtx *mpm_hcbd_ctx_ts;
    MpmCtx *mpm_hhd_ctx_ts;
    MpmCtx *mpm_hrhd_ctx_ts;
    MpmCtx *mpm_hmd_ctx_ts;
    MpmCtx *mpm_hcd_ctx_ts;
    MpmCtx *mpm_hrud_ctx_ts;
    MpmCtx *mpm_huad_ctx_ts;
    MpmCtx *mpm_hhhd_ctx_ts;
    MpmCtx *mpm_hrhhd_ctx_ts;
    MpmCtx *mpm_dnsquery_ctx_ts;

    MpmCtx *mpm_proto_tcp_ctx_tc;
    MpmCtx *mpm_proto_udp_ctx_tc;
    MpmCtx *mpm_stream_ctx_tc;
    MpmCtx *mpm_hsbd_ctx_tc;
    MpmCtx *mpm_hhd_ctx_tc;
    MpmCtx *mpm_hrhd_ctx_tc;
    MpmCtx *mpm_hcd_ctx_tc;
    MpmCtx *mpm_hsmd_ctx_tc;
    MpmCtx *mpm_hscd_ctx_tc;

    uint16_t mpm_uricontent_maxlen;

    /** the number of signatures in this sgh that have the filestore keyword
     *  set. */
    uint16_t filestore_cnt;

    /** Array with sig ptrs... size is sig_cnt * sizeof(Signature *) */
    Signature **match_array;

    /* 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          (1 << 0)
/** sigmatch is compatible with a ip only rule */
#define SIGMATCH_IPONLY_COMPAT  (1 << 1)
/** sigmatch is compatible with a decode event only rule */
#define SIGMATCH_DEONLY_COMPAT  (1 << 2)
/**< Flag to indicate that the signature inspects the packet payload */
#define SIGMATCH_PAYLOAD        (1 << 3)
/**< Flag to indicate that the signature is not built-in */
#define SIGMATCH_NOT_BUILT      (1 << 4)
/** sigmatch may have options, so the parser should be ready to
 *  deal with both cases */
#define SIGMATCH_OPTIONAL_OPT   (1 << 5)

/** Remember to add the options in SignatureIsIPOnly() at detect.c otherwise it wont be part of a signature group */

enum {
    DETECT_SID,
    DETECT_PRIORITY,
    DETECT_REV,
    DETECT_CLASSTYPE,
    DETECT_THRESHOLD,
    DETECT_METADATA,
    DETECT_REFERENCE,
    DETECT_TAG,
    DETECT_MSG,
    DETECT_CONTENT,
    DETECT_URICONTENT,
    DETECT_PCRE,
    DETECT_ACK,
    DETECT_SEQ,
    DETECT_DEPTH,
    DETECT_DISTANCE,
    DETECT_WITHIN,
    DETECT_OFFSET,
    DETECT_REPLACE,
    DETECT_NOCASE,
    DETECT_FAST_PATTERN,
    DETECT_RAWBYTES,
    DETECT_BYTETEST,
    DETECT_BYTEJUMP,
    DETECT_SAMEIP,
    DETECT_GEOIP,
    DETECT_IPPROTO,
    DETECT_FLOW,
    DETECT_WINDOW,
    DETECT_FTPBOUNCE,
    DETECT_ISDATAAT,
    DETECT_ID,
    DETECT_RPC,
    DETECT_DSIZE,
    DETECT_FLOWVAR,
    DETECT_FLOWVAR_POSTMATCH,
    DETECT_FLOWINT,
    DETECT_PKTVAR,
    DETECT_NOALERT,
    DETECT_FLOWBITS,
    DETECT_IPV4_CSUM,
    DETECT_TCPV4_CSUM,
    DETECT_TCPV6_CSUM,
    DETECT_UDPV4_CSUM,
    DETECT_UDPV6_CSUM,
    DETECT_ICMPV4_CSUM,
    DETECT_ICMPV6_CSUM,
    DETECT_STREAM_SIZE,
    DETECT_TTL,
    DETECT_ITYPE,
    DETECT_ICODE,
    DETECT_TOS,
    DETECT_ICMP_ID,
    DETECT_ICMP_SEQ,
    DETECT_DETECTION_FILTER,

    DETECT_DECODE_EVENT,
    DETECT_IPOPTS,
    DETECT_FLAGS,
    DETECT_FRAGBITS,
    DETECT_FRAGOFFSET,
    DETECT_GID,
    DETECT_MARK,

    DETECT_AL_TLS_VERSION,
    DETECT_AL_TLS_SUBJECT,
    DETECT_AL_TLS_ISSUERDN,
    DETECT_AL_TLS_FINGERPRINT,
    DETECT_AL_TLS_STORE,

    DETECT_AL_HTTP_COOKIE,
    DETECT_AL_HTTP_METHOD,
    DETECT_AL_URILEN,
    DETECT_AL_HTTP_CLIENT_BODY,
    DETECT_AL_HTTP_SERVER_BODY,
    DETECT_AL_HTTP_HEADER,
    DETECT_AL_HTTP_RAW_HEADER,
    DETECT_AL_HTTP_URI,
    DETECT_AL_HTTP_RAW_URI,
    DETECT_AL_HTTP_STAT_MSG,
    DETECT_AL_HTTP_STAT_CODE,
    DETECT_AL_HTTP_USER_AGENT,
    DETECT_AL_HTTP_HOST,
    DETECT_AL_HTTP_RAW_HOST,
    DETECT_AL_SSH_PROTOVERSION,
    DETECT_AL_SSH_SOFTWAREVERSION,
    DETECT_AL_SSL_VERSION,
    DETECT_AL_SSL_STATE,
    DETECT_BYTE_EXTRACT,
    DETECT_FILE_DATA,
    DETECT_PKT_DATA,
    DETECT_AL_APP_LAYER_EVENT,
    DETECT_AL_APP_LAYER_PROTOCOL,

    DETECT_DCE_IFACE,
    DETECT_DCE_OPNUM,
    DETECT_DCE_STUB_DATA,

    DETECT_ASN1,

    DETECT_ENGINE_EVENT,
    DETECT_STREAM_EVENT,

    DETECT_FILENAME,
    DETECT_FILEEXT,
    DETECT_FILESTORE,
    DETECT_FILEMAGIC,
    DETECT_FILEMD5,
    DETECT_FILESIZE,

    DETECT_L3PROTO,
    DETECT_LUA,
    DETECT_IPREP,

    DETECT_AL_DNS_QUERY,
    DETECT_AL_MODBUS,

    /* make sure this stays last */
    DETECT_TBLSIZE,
};

/* Table with all SigMatch registrations */
SigTableElmt sigmatch_table[DETECT_TBLSIZE];

/* detection api */
SigMatch *SigMatchAlloc(void);
Signature *SigFindSignatureBySidGid(DetectEngineCtx *, uint32_t, uint32_t);
void SigMatchSignaturesBuildMatchArray(DetectEngineThreadCtx *,
                                       Packet *, SignatureMask,
                                       uint16_t);
int SigMatchSignaturesBuildMatchArrayAddSignature(DetectEngineThreadCtx *,
                                                  Packet *, SignatureHeader *,
                                                  uint16_t);
void SigMatchFree(SigMatch *sm);
void SigCleanSignatures(DetectEngineCtx *);

void SigTableRegisterTests(void);
void SigRegisterTests(void);
void DetectSimdRegisterTests(void);
void TmModuleDetectRegister (void);

int SigGroupBuild(DetectEngineCtx *);
int SigGroupCleanup (DetectEngineCtx *de_ctx);
void SigAddressPrepareBidirectionals (DetectEngineCtx *);

char *DetectLoadCompleteSigPath(char *sig_file);
int SigLoadSignatures (DetectEngineCtx *, char *, int);
void SigTableList(const char *keyword);
void SigTableSetup(void);
int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx,
                       DetectEngineThreadCtx *det_ctx, Packet *p);

int SignatureIsIPOnly(DetectEngineCtx *de_ctx, Signature *s);
SigGroupHead *SigMatchSignaturesGetSgh(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p);

Signature *DetectGetTagSignature(void);

int SignatureIsFilestoring(Signature *);
int SignatureIsFilemagicInspecting(Signature *);
int SignatureIsFileMd5Inspecting(Signature *);
int SignatureIsFilesizeInspecting(Signature *);

int DetectRegisterThreadCtxFuncs(DetectEngineCtx *, const char *name, void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *), int);
void *DetectThreadCtxGetKeywordThreadCtx(DetectEngineThreadCtx *, int);

int SigMatchSignaturesRunPostMatch(ThreadVars *tv,
                                   DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p,
                                   Signature *s);

#endif /* __DETECT_H__ */

